initialize_mint.rs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. use {
  2. pinocchio::{
  3. account_info::AccountInfo,
  4. hint::likely,
  5. program_error::ProgramError,
  6. pubkey::Pubkey,
  7. sysvars::{rent::Rent, Sysvar},
  8. ProgramResult,
  9. },
  10. pinocchio_token_interface::{
  11. error::TokenError,
  12. state::{load_mut_unchecked, mint::Mint, Initializable},
  13. },
  14. };
  15. #[inline(always)]
  16. pub fn process_initialize_mint(
  17. accounts: &[AccountInfo],
  18. instruction_data: &[u8],
  19. rent_sysvar_account_provided: bool,
  20. ) -> ProgramResult {
  21. // Validates the instruction data.
  22. let (decimals, mint_authority, freeze_authority) = if instruction_data.len() >= 34 {
  23. // SAFETY: The minimum size of the instruction data is either 34 or 66 bytes:
  24. // - decimals (1 byte)
  25. // - mint_authority (32 bytes)
  26. // - option + freeze_authority (1 byte + 32 bytes)
  27. unsafe {
  28. let decimals = *instruction_data.get_unchecked(0);
  29. let mint_authority = &*(instruction_data.as_ptr().add(1) as *const Pubkey);
  30. let freeze_authority = if *instruction_data.get_unchecked(33) == 0 {
  31. None
  32. } else if likely(*instruction_data.get_unchecked(33) == 1)
  33. && instruction_data.len() >= 66
  34. {
  35. Some(&*(instruction_data.as_ptr().add(34) as *const Pubkey))
  36. } else {
  37. return Err(TokenError::InvalidInstruction.into());
  38. };
  39. (decimals, mint_authority, freeze_authority)
  40. }
  41. } else {
  42. return Err(TokenError::InvalidInstruction.into());
  43. };
  44. // Validates the accounts.
  45. let (mint_info, rent_sysvar_info) = if rent_sysvar_account_provided {
  46. let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else {
  47. return Err(ProgramError::NotEnoughAccountKeys);
  48. };
  49. (mint_info, Some(rent_sysvar_info))
  50. } else {
  51. let [mint_info, _remaining @ ..] = accounts else {
  52. return Err(ProgramError::NotEnoughAccountKeys);
  53. };
  54. (mint_info, None)
  55. };
  56. let mint_data_len = mint_info.data_len();
  57. let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info {
  58. // SAFETY: single immutable borrow to `rent_sysvar_info`; account ID and length
  59. // are checked by `from_account_info_unchecked`.
  60. let rent = unsafe { Rent::from_account_info_unchecked(rent_sysvar_info)? };
  61. rent.is_exempt(mint_info.lamports(), mint_data_len)
  62. } else {
  63. Rent::get()?.is_exempt(mint_info.lamports(), mint_data_len)
  64. };
  65. // SAFETY: single mutable borrow to `mint_info` account data.
  66. let mint = unsafe { load_mut_unchecked::<Mint>(mint_info.borrow_mut_data_unchecked())? };
  67. if mint.is_initialized()? {
  68. return Err(TokenError::AlreadyInUse.into());
  69. }
  70. if !is_exempt {
  71. return Err(TokenError::NotRentExempt.into());
  72. }
  73. // Initialize the mint.
  74. mint.set_initialized();
  75. mint.set_mint_authority(mint_authority);
  76. mint.decimals = decimals;
  77. if let Some(freeze_authority) = freeze_authority {
  78. mint.set_freeze_authority(freeze_authority);
  79. }
  80. Ok(())
  81. }