@@ -62,6 +62,7 @@ use crate::utils::{
62
62
check_valid_writable_account,
63
63
is_component_update,
64
64
pubkey_assign,
65
+ pubkey_clear,
65
66
pubkey_equal,
66
67
pubkey_is_zero,
67
68
pyth_assert,
@@ -705,3 +706,72 @@ pub fn set_min_pub(
705
706
706
707
Ok ( ( ) )
707
708
}
709
+
710
+ /// Delete a product account and remove it from the product list of its associated mapping account.
711
+ /// The deleted product account must not have any price accounts.
712
+ ///
713
+ /// This function allows you to delete products from non-tail mapping accounts. This ability is a
714
+ /// little weird, as it allows you to construct a list of multiple mapping accounts where non-tail
715
+ /// accounts have empty space. This is fine however; users should simply add new products to the
716
+ /// first available spot.
717
+ pub fn del_product (
718
+ program_id : & Pubkey ,
719
+ accounts : & [ AccountInfo ] ,
720
+ instruction_data : & [ u8 ] ,
721
+ ) -> ProgramResult {
722
+ let [ funding_account, mapping_account, product_account] = match accounts {
723
+ [ w, x, y] => Ok ( [ w, x, y] ) ,
724
+ _ => Err ( ProgramError :: InvalidArgument ) ,
725
+ } ?;
726
+
727
+ check_valid_funding_account ( funding_account) ?;
728
+ check_valid_signable_account ( program_id, mapping_account, size_of :: < pc_map_table_t > ( ) ) ?;
729
+ check_valid_signable_account ( program_id, product_account, PC_PROD_ACC_SIZE as usize ) ?;
730
+
731
+ {
732
+ let cmd_args = load :: < cmd_hdr_t > ( instruction_data) ?;
733
+ let mut mapping_data = load_checked :: < pc_map_table_t > ( mapping_account, cmd_args. ver_ ) ?;
734
+ let product_data = load_checked :: < pc_prod_t > ( product_account, cmd_args. ver_ ) ?;
735
+
736
+ // This assertion is just to make the subtractions below simpler
737
+ pyth_assert ( mapping_data. num_ >= 1 , ProgramError :: InvalidArgument ) ?;
738
+ pyth_assert (
739
+ pubkey_is_zero ( & product_data. px_acc_ ) ,
740
+ ProgramError :: InvalidArgument ,
741
+ ) ?;
742
+
743
+ let product_key = product_account. key . to_bytes ( ) ;
744
+ let product_index = mapping_data
745
+ . prod_
746
+ . iter ( )
747
+ . position ( |x| pubkey_equal ( x, & product_key) )
748
+ . ok_or ( ProgramError :: InvalidArgument ) ?;
749
+
750
+ let num_after_removal: usize = try_convert (
751
+ mapping_data
752
+ . num_
753
+ . checked_sub ( 1 )
754
+ . ok_or ( ProgramError :: InvalidArgument ) ?,
755
+ ) ?;
756
+
757
+ let last_key_bytes = mapping_data. prod_ [ num_after_removal] ;
758
+ pubkey_assign (
759
+ & mut mapping_data. prod_ [ product_index] ,
760
+ bytes_of ( & last_key_bytes) ,
761
+ ) ;
762
+ pubkey_clear ( & mut mapping_data. prod_ [ num_after_removal] ) ;
763
+ mapping_data. num_ = try_convert :: < _ , u32 > ( num_after_removal) ?;
764
+ mapping_data. size_ =
765
+ try_convert :: < _ , u32 > ( size_of :: < pc_map_table_t > ( ) - size_of_val ( & mapping_data. prod_ ) ) ?
766
+ + mapping_data. num_ * try_convert :: < _ , u32 > ( size_of :: < pc_pub_key_t > ( ) ) ?;
767
+ }
768
+
769
+ // Zero out the balance of the price account to delete it.
770
+ // Note that you can't use the system program's transfer instruction to do this operation, as
771
+ // that instruction fails if the source account has any data.
772
+ let lamports = product_account. lamports ( ) ;
773
+ * * product_account. lamports . borrow_mut ( ) = 0 ;
774
+ * * funding_account. lamports . borrow_mut ( ) += lamports;
775
+
776
+ Ok ( ( ) )
777
+ }
0 commit comments