initialize_mint.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. use core::{marker::PhantomData, mem::size_of};
  2. use pinocchio::{
  3. account_info::AccountInfo,
  4. program_error::ProgramError,
  5. pubkey::Pubkey,
  6. sysvars::{rent::Rent, Sysvar},
  7. ProgramResult,
  8. };
  9. use token_interface::{
  10. error::TokenError,
  11. state::{load_mut_unchecked, mint::Mint, Initializable},
  12. };
  13. #[inline(always)]
  14. pub fn process_initialize_mint(
  15. accounts: &[AccountInfo],
  16. instruction_data: &[u8],
  17. rent_sysvar_account: bool,
  18. ) -> ProgramResult {
  19. // Validates the instruction data.
  20. let args = InitializeMint::try_from_bytes(instruction_data)?;
  21. // Validates the accounts.
  22. let (mint_info, rent_sysvar_info) = if rent_sysvar_account {
  23. let [mint_info, rent_sysvar_info, _remaining @ ..] = accounts else {
  24. return Err(ProgramError::NotEnoughAccountKeys);
  25. };
  26. (mint_info, Some(rent_sysvar_info))
  27. } else {
  28. let [mint_info, _remaining @ ..] = accounts else {
  29. return Err(ProgramError::NotEnoughAccountKeys);
  30. };
  31. (mint_info, None)
  32. };
  33. let mint = unsafe { load_mut_unchecked::<Mint>(mint_info.borrow_mut_data_unchecked())? };
  34. if mint.is_initialized() {
  35. return Err(TokenError::AlreadyInUse.into());
  36. }
  37. // Check rent-exempt status of the mint account.
  38. let is_exempt = if let Some(rent_sysvar_info) = rent_sysvar_info {
  39. let rent = unsafe { Rent::from_bytes(rent_sysvar_info.borrow_data_unchecked()) };
  40. rent.is_exempt(mint_info.lamports(), size_of::<Mint>())
  41. } else {
  42. Rent::get()?.is_exempt(mint_info.lamports(), size_of::<Mint>())
  43. };
  44. if !is_exempt {
  45. return Err(TokenError::NotRentExempt.into());
  46. }
  47. // Initialize the mint.
  48. mint.set_initialized(true);
  49. mint.set_mint_authority(args.mint_authority());
  50. mint.decimals = args.decimals();
  51. if let Some(freeze_authority) = args.freeze_authority() {
  52. mint.set_freeze_authority(freeze_authority);
  53. }
  54. Ok(())
  55. }
  56. /// Instruction data for the `InitializeMint` instruction.
  57. pub struct InitializeMint<'a> {
  58. raw: *const u8,
  59. _data: PhantomData<&'a [u8]>,
  60. }
  61. impl InitializeMint<'_> {
  62. #[inline]
  63. pub fn try_from_bytes(bytes: &[u8]) -> Result<InitializeMint, ProgramError> {
  64. // The minimum expected size of the instruction data.
  65. // - decimals (1 byte)
  66. // - mint_authority (32 bytes)
  67. // - option + freeze_authority (1 byte + 32 bytes)
  68. if bytes.len() < 34 {
  69. return Err(ProgramError::InvalidInstructionData);
  70. }
  71. Ok(InitializeMint {
  72. raw: bytes.as_ptr(),
  73. _data: PhantomData,
  74. })
  75. }
  76. #[inline]
  77. pub fn decimals(&self) -> u8 {
  78. unsafe { *self.raw }
  79. }
  80. #[inline]
  81. pub fn mint_authority(&self) -> &Pubkey {
  82. unsafe { &*(self.raw.add(1) as *const Pubkey) }
  83. }
  84. #[inline]
  85. pub fn freeze_authority(&self) -> Option<&Pubkey> {
  86. unsafe {
  87. if *self.raw.add(33) == 0 {
  88. Option::None
  89. } else {
  90. Option::Some(&*(self.raw.add(34) as *const Pubkey))
  91. }
  92. }
  93. }
  94. }