@@ -15,6 +15,8 @@ use std::mem::size_of;
1515pub const MIN_SIGNERS : usize = 1 ;
1616/// Maximum number of multisignature signers (max N)
1717pub const MAX_SIGNERS : usize = 11 ;
18+ /// Serialized length of a u64, for unpacking
19+ const U64_BYTES : usize = 8 ;
1820
1921/// Instructions supported by the token program.
2022#[ repr( C ) ]
@@ -519,59 +521,19 @@ impl<'a> TokenInstruction<'a> {
519521 10 => Self :: FreezeAccount ,
520522 11 => Self :: ThawAccount ,
521523 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) ?;
533525 Self :: TransferChecked { amount, decimals }
534526 }
535527 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) ?;
547529 Self :: ApproveChecked { amount, decimals }
548530 }
549531 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) ?;
561533 Self :: MintToChecked { amount, decimals }
562534 }
563535 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) ?;
575537 Self :: BurnChecked { amount, decimals }
576538 }
577539 16 => {
@@ -600,15 +562,7 @@ impl<'a> TokenInstruction<'a> {
600562 21 => Self :: GetAccountDataSize ,
601563 22 => Self :: InitializeImmutableOwner ,
602564 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) ?;
612566 Self :: AmountToUiAmount { amount }
613567 }
614568 24 => {
@@ -760,6 +714,21 @@ impl<'a> TokenInstruction<'a> {
760714 COption :: None => buf. push ( 0 ) ,
761715 }
762716 }
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+ }
763732}
764733
765734/// Specifies the authority type for SetAuthority instructions
@@ -1708,8 +1677,11 @@ mod test {
17081677 #[ test]
17091678 fn test_instruction_unpack_panic ( ) {
17101679 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+ }
17131685 }
17141686 }
17151687}
0 commit comments