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

Commit 94861a3

Browse files
Add approve, revoke subcommands (#540)
* Add approve, revoke subcommands * Use get_token_account api to reduce rpc calls
1 parent c24e824 commit 94861a3

File tree

1 file changed

+148
-21
lines changed

1 file changed

+148
-21
lines changed

token/cli/src/main.rs

Lines changed: 148 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -229,18 +229,13 @@ fn command_transfer(
229229
ui_amount, sender, recipient
230230
);
231231

232-
let sender_token_balance = config
233-
.rpc_client
234-
.get_token_account_balance_with_commitment(&sender, config.commitment_config)?
235-
.value;
236232
let source_account = config
237233
.rpc_client
238-
.get_account_with_commitment(&sender, config.commitment_config)?
234+
.get_token_account_with_commitment(&sender, config.commitment_config)?
239235
.value
240-
.unwrap_or_default();
241-
let data = source_account.data.to_vec();
242-
let mint_pubkey = Account::unpack_from_slice(&data)?.mint;
243-
let amount = spl_token::ui_amount_to_amount(ui_amount, sender_token_balance.decimals);
236+
.ok_or_else(|| format!("Could not find token account {}", sender))?;
237+
let mint_pubkey = Pubkey::from_str(&source_account.mint)?;
238+
let amount = spl_token::ui_amount_to_amount(ui_amount, source_account.token_amount.decimals);
244239

245240
let mut transaction = Transaction::new_with_payer(
246241
&[transfer_checked(
@@ -251,7 +246,7 @@ fn command_transfer(
251246
&config.owner.pubkey(),
252247
&[],
253248
amount,
254-
sender_token_balance.decimals,
249+
source_account.token_amount.decimals,
255250
)?],
256251
Some(&config.fee_payer.pubkey()),
257252
);
@@ -270,18 +265,14 @@ fn command_transfer(
270265
fn command_burn(config: &Config, source: Pubkey, ui_amount: f64) -> CommandResult {
271266
println!("Burn {} tokens\n Source: {}", ui_amount, source);
272267

273-
let source_token_balance = config
274-
.rpc_client
275-
.get_token_account_balance_with_commitment(&source, config.commitment_config)?
276-
.value;
277268
let source_account = config
278269
.rpc_client
279-
.get_account_with_commitment(&source, config.commitment_config)?
270+
.get_token_account_with_commitment(&source, config.commitment_config)?
280271
.value
281-
.unwrap_or_default();
282-
let data = source_account.data.to_vec();
283-
let mint_pubkey = Account::unpack_from_slice(&data)?.mint;
284-
let amount = spl_token::ui_amount_to_amount(ui_amount, source_token_balance.decimals);
272+
.ok_or_else(|| format!("Could not find token account {}", source))?;
273+
let mint_pubkey = Pubkey::from_str(&source_account.mint)?;
274+
let amount = spl_token::ui_amount_to_amount(ui_amount, source_account.token_amount.decimals);
275+
285276
let mut transaction = Transaction::new_with_payer(
286277
&[burn_checked(
287278
&spl_token::id(),
@@ -290,7 +281,7 @@ fn command_burn(config: &Config, source: Pubkey, ui_amount: f64) -> CommandResul
290281
&config.owner.pubkey(),
291282
&[],
292283
amount,
293-
source_token_balance.decimals,
284+
source_account.token_amount.decimals,
294285
)?],
295286
Some(&config.fee_payer.pubkey()),
296287
);
@@ -482,6 +473,88 @@ fn command_unwrap(config: &Config, address: Pubkey) -> CommandResult {
482473
Ok(Some(transaction))
483474
}
484475

476+
fn command_approve(
477+
config: &Config,
478+
account: Pubkey,
479+
ui_amount: f64,
480+
delegate: Pubkey,
481+
) -> CommandResult {
482+
println!(
483+
"Approve {} tokens\n Account: {}\n Delegate: {}",
484+
ui_amount, account, delegate
485+
);
486+
487+
let source_account = config
488+
.rpc_client
489+
.get_token_account_with_commitment(&account, config.commitment_config)?
490+
.value
491+
.ok_or_else(|| format!("Could not find token account {}", account))?;
492+
let mint_pubkey = Pubkey::from_str(&source_account.mint)?;
493+
let amount = spl_token::ui_amount_to_amount(ui_amount, source_account.token_amount.decimals);
494+
495+
let mut transaction = Transaction::new_with_payer(
496+
&[approve_checked(
497+
&spl_token::id(),
498+
&account,
499+
&mint_pubkey,
500+
&delegate,
501+
&config.owner.pubkey(),
502+
&[],
503+
amount,
504+
source_account.token_amount.decimals,
505+
)?],
506+
Some(&config.fee_payer.pubkey()),
507+
);
508+
509+
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
510+
check_fee_payer_balance(
511+
config,
512+
fee_calculator.calculate_fee(&transaction.message(), None),
513+
)?;
514+
let mut signers = vec![config.fee_payer.as_ref(), config.owner.as_ref()];
515+
unique_signers!(signers);
516+
transaction.sign(&signers, recent_blockhash);
517+
Ok(Some(transaction))
518+
}
519+
520+
fn command_revoke(config: &Config, account: Pubkey) -> CommandResult {
521+
let source_account = config
522+
.rpc_client
523+
.get_token_account_with_commitment(&account, config.commitment_config)?
524+
.value
525+
.ok_or_else(|| format!("Could not find token account {}", account))?;
526+
let delegate = source_account.delegate;
527+
528+
if let Some(delegate) = delegate {
529+
println!(
530+
"Revoking approval\n Account: {}\n Delegate: {}",
531+
account, delegate
532+
);
533+
} else {
534+
return Err(format!("No delegate on account {}", account).into());
535+
}
536+
537+
let mut transaction = Transaction::new_with_payer(
538+
&[revoke(
539+
&spl_token::id(),
540+
&account,
541+
&config.owner.pubkey(),
542+
&[],
543+
)?],
544+
Some(&config.fee_payer.pubkey()),
545+
);
546+
547+
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
548+
check_fee_payer_balance(
549+
config,
550+
fee_calculator.calculate_fee(&transaction.message(), None),
551+
)?;
552+
let mut signers = vec![config.fee_payer.as_ref(), config.owner.as_ref()];
553+
unique_signers!(signers);
554+
transaction.sign(&signers, recent_blockhash);
555+
Ok(Some(transaction))
556+
}
557+
485558
fn command_balance(config: &Config, address: Pubkey) -> CommandResult {
486559
let balance = config
487560
.rpc_client
@@ -964,12 +1037,56 @@ fn main() {
9641037
.about("Query details of an SPL Token account by address")
9651038
.arg(
9661039
Arg::with_name("address")
1040+
.validator(is_pubkey_or_keypair)
1041+
.value_name("TOKEN_ACCOUNT_ADDRESS")
1042+
.takes_value(true)
1043+
.index(1)
1044+
.required(true)
1045+
.help("The address of the SPL Token account to query"),
1046+
),
1047+
)
1048+
.subcommand(
1049+
SubCommand::with_name("approve")
1050+
.about("Approve a delegate for a token account")
1051+
.arg(
1052+
Arg::with_name("account")
1053+
.validator(is_pubkey_or_keypair)
1054+
.value_name("TOKEN_ACCOUNT_ADDRESS")
1055+
.takes_value(true)
1056+
.index(1)
1057+
.required(true)
1058+
.help("The address of the token account to delegate"),
1059+
)
1060+
.arg(
1061+
Arg::with_name("amount")
1062+
.validator(is_amount)
1063+
.value_name("TOKEN_AMOUNT")
1064+
.takes_value(true)
1065+
.index(2)
1066+
.required(true)
1067+
.help("Amount to approve, in tokens"),
1068+
)
1069+
.arg(
1070+
Arg::with_name("delegate")
1071+
.validator(is_pubkey_or_keypair)
1072+
.value_name("DELEGATE_TOKEN_ACCOUNT_ADDRESS")
1073+
.takes_value(true)
1074+
.index(3)
1075+
.required(true)
1076+
.help("The token account address of delegate"),
1077+
),
1078+
)
1079+
.subcommand(
1080+
SubCommand::with_name("revoke")
1081+
.about("Revoke a delegate's authority")
1082+
.arg(
1083+
Arg::with_name("account")
9671084
.validator(is_pubkey_or_keypair)
9681085
.value_name("TOKEN_ACCOUNT_ADDRESS")
9691086
.takes_value(true)
9701087
.index(1)
9711088
.required(true)
972-
.help("The address of the SPL Token account to query"),
1089+
.help("The address of the token account"),
9731090
),
9741091
)
9751092
.get_matches();
@@ -1114,6 +1231,16 @@ fn main() {
11141231
let address = pubkey_of(arg_matches, "address").unwrap();
11151232
command_unwrap(&config, address)
11161233
}
1234+
("approve", Some(arg_matches)) => {
1235+
let account = pubkey_of(arg_matches, "account").unwrap();
1236+
let amount = value_t_or_exit!(arg_matches, "amount", f64);
1237+
let delegate = pubkey_of(arg_matches, "delegate").unwrap();
1238+
command_approve(&config, account, amount, delegate)
1239+
}
1240+
("revoke", Some(arg_matches)) => {
1241+
let account = pubkey_of(arg_matches, "account").unwrap();
1242+
command_revoke(&config, account)
1243+
}
11171244
("balance", Some(arg_matches)) => {
11181245
let address = pubkey_of(arg_matches, "address").unwrap();
11191246
command_balance(&config, address)

0 commit comments

Comments
 (0)