@@ -229,18 +229,13 @@ fn command_transfer(
229
229
ui_amount, sender, recipient
230
230
) ;
231
231
232
- let sender_token_balance = config
233
- . rpc_client
234
- . get_token_account_balance_with_commitment ( & sender, config. commitment_config ) ?
235
- . value ;
236
232
let source_account = config
237
233
. rpc_client
238
- . get_account_with_commitment ( & sender, config. commitment_config ) ?
234
+ . get_token_account_with_commitment ( & sender, config. commitment_config ) ?
239
235
. 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 ) ;
244
239
245
240
let mut transaction = Transaction :: new_with_payer (
246
241
& [ transfer_checked (
@@ -251,7 +246,7 @@ fn command_transfer(
251
246
& config. owner . pubkey ( ) ,
252
247
& [ ] ,
253
248
amount,
254
- sender_token_balance . decimals ,
249
+ source_account . token_amount . decimals ,
255
250
) ?] ,
256
251
Some ( & config. fee_payer . pubkey ( ) ) ,
257
252
) ;
@@ -270,18 +265,14 @@ fn command_transfer(
270
265
fn command_burn ( config : & Config , source : Pubkey , ui_amount : f64 ) -> CommandResult {
271
266
println ! ( "Burn {} tokens\n Source: {}" , ui_amount, source) ;
272
267
273
- let source_token_balance = config
274
- . rpc_client
275
- . get_token_account_balance_with_commitment ( & source, config. commitment_config ) ?
276
- . value ;
277
268
let source_account = config
278
269
. rpc_client
279
- . get_account_with_commitment ( & source, config. commitment_config ) ?
270
+ . get_token_account_with_commitment ( & source, config. commitment_config ) ?
280
271
. 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
+
285
276
let mut transaction = Transaction :: new_with_payer (
286
277
& [ burn_checked (
287
278
& spl_token:: id ( ) ,
@@ -290,7 +281,7 @@ fn command_burn(config: &Config, source: Pubkey, ui_amount: f64) -> CommandResul
290
281
& config. owner . pubkey ( ) ,
291
282
& [ ] ,
292
283
amount,
293
- source_token_balance . decimals ,
284
+ source_account . token_amount . decimals ,
294
285
) ?] ,
295
286
Some ( & config. fee_payer . pubkey ( ) ) ,
296
287
) ;
@@ -482,6 +473,88 @@ fn command_unwrap(config: &Config, address: Pubkey) -> CommandResult {
482
473
Ok ( Some ( transaction) )
483
474
}
484
475
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
+
485
558
fn command_balance ( config : & Config , address : Pubkey ) -> CommandResult {
486
559
let balance = config
487
560
. rpc_client
@@ -964,12 +1037,56 @@ fn main() {
964
1037
. about ( "Query details of an SPL Token account by address" )
965
1038
. arg (
966
1039
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" )
967
1084
. validator ( is_pubkey_or_keypair)
968
1085
. value_name ( "TOKEN_ACCOUNT_ADDRESS" )
969
1086
. takes_value ( true )
970
1087
. index ( 1 )
971
1088
. required ( true )
972
- . help ( "The address of the SPL Token account to query " ) ,
1089
+ . help ( "The address of the token account" ) ,
973
1090
) ,
974
1091
)
975
1092
. get_matches ( ) ;
@@ -1114,6 +1231,16 @@ fn main() {
1114
1231
let address = pubkey_of ( arg_matches, "address" ) . unwrap ( ) ;
1115
1232
command_unwrap ( & config, address)
1116
1233
}
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
+ }
1117
1244
( "balance" , Some ( arg_matches) ) => {
1118
1245
let address = pubkey_of ( arg_matches, "address" ) . unwrap ( ) ;
1119
1246
command_balance ( & config, address)
0 commit comments