@@ -649,6 +649,7 @@ fn command_transfer(
649
649
memo : Option < String > ,
650
650
bulk_signers : BulkSigners ,
651
651
no_wait : bool ,
652
+ allow_non_system_account_recipient : bool ,
652
653
) -> CommandResult {
653
654
let sender = if let Some ( sender) = sender {
654
655
sender
@@ -709,17 +710,31 @@ fn command_transfer(
709
710
. get_account_with_commitment ( & recipient, config. rpc_client . commitment ( ) ) ?
710
711
. value
711
712
. map ( |account| {
712
- account. owner == config. program_id && account. data . len ( ) == Account :: LEN
713
+ (
714
+ account. owner == config. program_id && account. data . len ( ) == Account :: LEN ,
715
+ account. owner == system_program:: id ( ) ,
716
+ )
713
717
} ) ;
714
-
715
- if recipient_account_info. is_none ( ) && !allow_unfunded_recipient {
718
+ if let Some ( ( recipient_is_token_account, recipient_is_system_account) ) =
719
+ recipient_account_info
720
+ {
721
+ if !recipient_is_token_account
722
+ && !recipient_is_system_account
723
+ && !allow_non_system_account_recipient
724
+ {
725
+ return Err ( "Error: The recipient address is not owned by the System Program. \
726
+ Add `--allow-non-system-account-recipient` to complete the transfer. \
727
+ ". into ( ) ) ;
728
+ }
729
+ } else if recipient_account_info. is_none ( ) && !allow_unfunded_recipient {
716
730
return Err ( "Error: The recipient address is not funded. \
717
- Add `--allow-unfunded-recipient` to complete the transfer \
731
+ Add `--allow-unfunded-recipient` to complete the transfer. \
718
732
"
719
733
. into ( ) ) ;
720
734
}
721
-
722
- recipient_account_info. unwrap_or ( false )
735
+ recipient_account_info
736
+ . map ( |( recipient_is_token_account, _) | recipient_is_token_account)
737
+ . unwrap_or ( false )
723
738
} else {
724
739
!recipient_is_ata_owner
725
740
} ;
@@ -2024,6 +2039,12 @@ fn app<'a, 'b>(
2024
2039
. takes_value ( false )
2025
2040
. help ( "Return signature immediately after submitting the transaction, instead of waiting for confirmations" ) ,
2026
2041
)
2042
+ . arg (
2043
+ Arg :: with_name ( "allow_non_system_account_recipient" )
2044
+ . long ( "allow-non-system-account-recipient" )
2045
+ . takes_value ( false )
2046
+ . help ( "Send tokens to the recipient even if the recipient is not a wallet owned by System Program." ) ,
2047
+ )
2027
2048
. arg (
2028
2049
Arg :: with_name ( "recipient_is_ata_owner" )
2029
2050
. long ( "recipient-is-ata-owner" )
@@ -2785,6 +2806,7 @@ fn process_command(
2785
2806
memo,
2786
2807
bulk_signers,
2787
2808
arg_matches. is_present ( "no_wait" ) ,
2809
+ arg_matches. is_present ( "allow_non_system_account_recipient" ) ,
2788
2810
)
2789
2811
}
2790
2812
( "burn" , arg_matches) => {
@@ -3490,6 +3512,65 @@ mod tests {
3490
3512
assert_eq ! ( ui_account. token_amount. amount, "90" ) ;
3491
3513
}
3492
3514
3515
+ #[ test]
3516
+ fn failing_to_allow_non_system_account_recipient ( ) {
3517
+ let ( test_validator, payer) = validator_for_test ( ) ;
3518
+ let config = test_config ( & test_validator, & payer, & spl_token:: id ( ) ) ;
3519
+
3520
+ let token = create_token ( & config, & payer) ;
3521
+ let source = create_associated_account ( & config, & payer, token) ;
3522
+ let recipient = token. to_string ( ) ;
3523
+ let ui_amount = 100.0 ;
3524
+ mint_tokens ( & config, & payer, token, ui_amount, source) ;
3525
+ let result = process_test_command (
3526
+ & config,
3527
+ & payer,
3528
+ & [
3529
+ "spl-token" ,
3530
+ "transfer" ,
3531
+ "--fund-recipient" ,
3532
+ & token. to_string ( ) ,
3533
+ "10" ,
3534
+ & recipient,
3535
+ ] ,
3536
+ ) ;
3537
+ assert ! ( result. is_err( ) ) ;
3538
+ }
3539
+
3540
+ #[ test]
3541
+ fn allow_non_system_account_recipient ( ) {
3542
+ let ( test_validator, payer) = validator_for_test ( ) ;
3543
+ let config = test_config ( & test_validator, & payer, & spl_token:: id ( ) ) ;
3544
+
3545
+ let token = create_token ( & config, & payer) ;
3546
+ let source = create_associated_account ( & config, & payer, token) ;
3547
+ let recipient = token. to_string ( ) ;
3548
+ let ui_amount = 100.0 ;
3549
+ mint_tokens ( & config, & payer, token, ui_amount, source) ;
3550
+ let result = process_test_command (
3551
+ & config,
3552
+ & payer,
3553
+ & [
3554
+ "spl-token" ,
3555
+ "transfer" ,
3556
+ "--fund-recipient" ,
3557
+ "--allow-non-system-account-recipient" ,
3558
+ "--allow-unfunded-recipient" ,
3559
+ & token. to_string ( ) ,
3560
+ "10" ,
3561
+ & recipient,
3562
+ ] ,
3563
+ ) ;
3564
+ result. unwrap ( ) ;
3565
+
3566
+ let ui_account = config
3567
+ . rpc_client
3568
+ . get_token_account ( & source)
3569
+ . unwrap ( )
3570
+ . unwrap ( ) ;
3571
+ assert_eq ! ( ui_account. token_amount. amount, "90" ) ;
3572
+ }
3573
+
3493
3574
#[ test]
3494
3575
fn disable_mint_authority ( ) {
3495
3576
let ( test_validator, payer) = validator_for_test ( ) ;
0 commit comments