@@ -15,6 +15,8 @@ use std::mem::size_of;
15
15
pub const MIN_SIGNERS : usize = 1 ;
16
16
/// Maximum number of multisignature signers (max N)
17
17
pub const MAX_SIGNERS : usize = 11 ;
18
+ /// Serialized length of a u64, for unpacking
19
+ const U64_BYTES : usize = 8 ;
18
20
19
21
/// Instructions supported by the token program.
20
22
#[ repr( C ) ]
@@ -519,59 +521,19 @@ impl<'a> TokenInstruction<'a> {
519
521
10 => Self :: FreezeAccount ,
520
522
11 => Self :: ThawAccount ,
521
523
12 => {
522
- if rest. len ( ) < 8 {
523
- return Err ( TokenError :: InvalidInstruction . into ( ) ) ;
524
- }
525
- let ( amount, rest) = rest. split_at ( 8 ) ;
526
- let amount = amount
527
- . try_into ( )
528
- . ok ( )
529
- . map ( u64:: from_le_bytes)
530
- . ok_or ( InvalidInstruction ) ?;
531
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
532
-
524
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
533
525
Self :: TransferChecked { amount, decimals }
534
526
}
535
527
13 => {
536
- if rest. len ( ) < 8 {
537
- return Err ( TokenError :: InvalidInstruction . into ( ) ) ;
538
- }
539
- let ( amount, rest) = rest. split_at ( 8 ) ;
540
- let amount = amount
541
- . try_into ( )
542
- . ok ( )
543
- . map ( u64:: from_le_bytes)
544
- . ok_or ( InvalidInstruction ) ?;
545
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
546
-
528
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
547
529
Self :: ApproveChecked { amount, decimals }
548
530
}
549
531
14 => {
550
- if rest. len ( ) < 8 {
551
- return Err ( TokenError :: InvalidInstruction . into ( ) ) ;
552
- }
553
- let ( amount, rest) = rest. split_at ( 8 ) ;
554
- let amount = amount
555
- . try_into ( )
556
- . ok ( )
557
- . map ( u64:: from_le_bytes)
558
- . ok_or ( InvalidInstruction ) ?;
559
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
560
-
532
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
561
533
Self :: MintToChecked { amount, decimals }
562
534
}
563
535
15 => {
564
- if rest. len ( ) < 8 {
565
- return Err ( TokenError :: InvalidInstruction . into ( ) ) ;
566
- }
567
- let ( amount, rest) = rest. split_at ( 8 ) ;
568
- let amount = amount
569
- . try_into ( )
570
- . ok ( )
571
- . map ( u64:: from_le_bytes)
572
- . ok_or ( InvalidInstruction ) ?;
573
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
574
-
536
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
575
537
Self :: BurnChecked { amount, decimals }
576
538
}
577
539
16 => {
@@ -600,15 +562,7 @@ impl<'a> TokenInstruction<'a> {
600
562
21 => Self :: GetAccountDataSize ,
601
563
22 => Self :: InitializeImmutableOwner ,
602
564
23 => {
603
- if rest. len ( ) < 8 {
604
- return Err ( TokenError :: InvalidInstruction . into ( ) ) ;
605
- }
606
- let ( amount, _rest) = rest. split_at ( 8 ) ;
607
- let amount = amount
608
- . try_into ( )
609
- . ok ( )
610
- . map ( u64:: from_le_bytes)
611
- . ok_or ( InvalidInstruction ) ?;
565
+ let ( amount, _rest) = Self :: unpack_u64 ( rest) ?;
612
566
Self :: AmountToUiAmount { amount }
613
567
}
614
568
24 => {
@@ -760,6 +714,21 @@ impl<'a> TokenInstruction<'a> {
760
714
COption :: None => buf. push ( 0 ) ,
761
715
}
762
716
}
717
+
718
+ fn unpack_u64 ( input : & [ u8 ] ) -> Result < ( u64 , & [ u8 ] ) , ProgramError > {
719
+ let value = input
720
+ . get ( ..U64_BYTES )
721
+ . and_then ( |slice| slice. try_into ( ) . ok ( ) )
722
+ . map ( u64:: from_le_bytes)
723
+ . ok_or ( TokenError :: InvalidInstruction ) ?;
724
+ Ok ( ( value, & input[ U64_BYTES ..] ) )
725
+ }
726
+
727
+ fn unpack_amount_decimals ( input : & [ u8 ] ) -> Result < ( u64 , u8 , & [ u8 ] ) , ProgramError > {
728
+ let ( amount, rest) = Self :: unpack_u64 ( input) ?;
729
+ let ( & decimals, rest) = rest. split_first ( ) . ok_or ( TokenError :: InvalidInstruction ) ?;
730
+ Ok ( ( amount, decimals, rest) )
731
+ }
763
732
}
764
733
765
734
/// Specifies the authority type for SetAuthority instructions
@@ -1708,8 +1677,11 @@ mod test {
1708
1677
#[ test]
1709
1678
fn test_instruction_unpack_panic ( ) {
1710
1679
for i in 0 ..255u8 {
1711
- let expect = Vec :: from ( [ i, 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 ] ) ;
1712
- _ = TokenInstruction :: unpack ( & expect[ 0 ..2 ] ) ;
1680
+ for j in 1 ..10 {
1681
+ let mut data = vec ! [ 0 ; j] ;
1682
+ data[ 0 ] = i;
1683
+ let _no_panic = TokenInstruction :: unpack ( & data) ;
1684
+ }
1713
1685
}
1714
1686
}
1715
1687
}
0 commit comments