entrypoint.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. use {
  2. crate::processor::*,
  3. pinocchio::{
  4. account_info::AccountInfo,
  5. no_allocator, nostd_panic_handler, program_entrypoint,
  6. program_error::{ProgramError, ToStr},
  7. pubkey::Pubkey,
  8. ProgramResult,
  9. },
  10. spl_token_interface::error::TokenError,
  11. };
  12. program_entrypoint!(process_instruction);
  13. // Do not allocate memory.
  14. no_allocator!();
  15. // Use the no_std panic handler.
  16. nostd_panic_handler!();
  17. /// Log an error.
  18. #[cold]
  19. fn log_error(error: &ProgramError) {
  20. pinocchio::log::sol_log(error.to_str::<TokenError>());
  21. }
  22. /// Process an instruction.
  23. ///
  24. /// In the first stage, the entrypoint checks the discriminator of the
  25. /// instruction data to determine whether the instruction is a "batch"
  26. /// instruction or a "regular" instruction. This avoids nesting of "batch"
  27. /// instructions, since it is not sound to have a "batch" instruction inside
  28. /// another "batch" instruction.
  29. #[inline(always)]
  30. pub fn process_instruction(
  31. _program_id: &Pubkey,
  32. accounts: &[AccountInfo],
  33. instruction_data: &[u8],
  34. ) -> ProgramResult {
  35. let [discriminator, remaining @ ..] = instruction_data else {
  36. return Err(ProgramError::InvalidInstructionData);
  37. };
  38. let result = if *discriminator == 255 {
  39. // 255 - Batch
  40. #[cfg(feature = "logging")]
  41. pinocchio::msg!("Instruction: Batch");
  42. process_batch(accounts, remaining)
  43. } else {
  44. inner_process_instruction(accounts, instruction_data)
  45. };
  46. result.inspect_err(log_error)
  47. }
  48. /// Process a "regular" instruction.
  49. ///
  50. /// The processor of the token program is divided into two parts to reduce the
  51. /// overhead of having a large `match` statement. The first part of the
  52. /// processor handles the most common instructions, while the second part
  53. /// handles the remaining instructions.
  54. ///
  55. /// The rationale is to reduce the overhead of making multiple comparisons for
  56. /// popular instructions.
  57. ///
  58. /// Instructions on the first part of the inner processor:
  59. ///
  60. /// - `0`: `InitializeMint`
  61. /// - `1`: `InitializeAccount`
  62. /// - `3`: `Transfer`
  63. /// - `7`: `MintTo`
  64. /// - `9`: `CloseAccount`
  65. /// - `16`: `InitializeAccount2`
  66. /// - `18`: `InitializeAccount3`
  67. /// - `20`: `InitializeMint2`
  68. #[inline(always)]
  69. pub(crate) fn inner_process_instruction(
  70. accounts: &[AccountInfo],
  71. instruction_data: &[u8],
  72. ) -> ProgramResult {
  73. let [discriminator, instruction_data @ ..] = instruction_data else {
  74. return Err(ProgramError::InvalidInstructionData);
  75. };
  76. match *discriminator {
  77. // 0 - InitializeMint
  78. 0 => {
  79. #[cfg(feature = "logging")]
  80. pinocchio::msg!("Instruction: InitializeMint");
  81. process_initialize_mint(accounts, instruction_data)
  82. }
  83. // 1 - InitializeAccount
  84. 1 => {
  85. #[cfg(feature = "logging")]
  86. pinocchio::msg!("Instruction: InitializeAccount");
  87. process_initialize_account(accounts)
  88. }
  89. // 3 - Transfer
  90. 3 => {
  91. #[cfg(feature = "logging")]
  92. pinocchio::msg!("Instruction: Transfer");
  93. process_transfer(accounts, instruction_data)
  94. }
  95. // 7 - MintTo
  96. 7 => {
  97. #[cfg(feature = "logging")]
  98. pinocchio::msg!("Instruction: MintTo");
  99. process_mint_to(accounts, instruction_data)
  100. }
  101. // 9 - CloseAccount
  102. 9 => {
  103. #[cfg(feature = "logging")]
  104. pinocchio::msg!("Instruction: CloseAccount");
  105. process_close_account(accounts)
  106. }
  107. // 16 - InitializeAccount2
  108. 16 => {
  109. #[cfg(feature = "logging")]
  110. pinocchio::msg!("Instruction: InitializeAccount2");
  111. process_initialize_account2(accounts, instruction_data)
  112. }
  113. // 18 - InitializeAccount3
  114. 18 => {
  115. #[cfg(feature = "logging")]
  116. pinocchio::msg!("Instruction: InitializeAccount3");
  117. process_initialize_account3(accounts, instruction_data)
  118. }
  119. // 20 - InitializeMint2
  120. 20 => {
  121. #[cfg(feature = "logging")]
  122. pinocchio::msg!("Instruction: InitializeMint2");
  123. process_initialize_mint2(accounts, instruction_data)
  124. }
  125. d => inner_process_remaining_instruction(accounts, instruction_data, d),
  126. }
  127. }
  128. /// Process a remaining "regular" instruction.
  129. ///
  130. /// This function is called by the [`inner_process_instruction`] function if the
  131. /// discriminator does not match any of the common instructions. This function
  132. /// is used to reduce the overhead of having a large `match` statement in the
  133. /// [`inner_process_instruction`] function.
  134. fn inner_process_remaining_instruction(
  135. accounts: &[AccountInfo],
  136. instruction_data: &[u8],
  137. discriminator: u8,
  138. ) -> ProgramResult {
  139. match discriminator {
  140. // 2 - InitializeMultisig
  141. 2 => {
  142. #[cfg(feature = "logging")]
  143. pinocchio::msg!("Instruction: InitializeMultisig");
  144. process_initialize_multisig(accounts, instruction_data)
  145. }
  146. // 4 - Approve
  147. 4 => {
  148. #[cfg(feature = "logging")]
  149. pinocchio::msg!("Instruction: Approve");
  150. process_approve(accounts, instruction_data)
  151. }
  152. // 5 - Revoke
  153. 5 => {
  154. #[cfg(feature = "logging")]
  155. pinocchio::msg!("Instruction: Revoke");
  156. process_revoke(accounts, instruction_data)
  157. }
  158. // 6 - SetAuthority
  159. 6 => {
  160. #[cfg(feature = "logging")]
  161. pinocchio::msg!("Instruction: SetAuthority");
  162. process_set_authority(accounts, instruction_data)
  163. }
  164. // 8 - Burn
  165. 8 => {
  166. #[cfg(feature = "logging")]
  167. pinocchio::msg!("Instruction: Burn");
  168. process_burn(accounts, instruction_data)
  169. }
  170. // 10 - FreezeAccount
  171. 10 => {
  172. #[cfg(feature = "logging")]
  173. pinocchio::msg!("Instruction: FreezeAccount");
  174. process_freeze_account(accounts)
  175. }
  176. // 11 - ThawAccount
  177. 11 => {
  178. #[cfg(feature = "logging")]
  179. pinocchio::msg!("Instruction: ThawAccount");
  180. process_thaw_account(accounts)
  181. }
  182. // 12 - TransferChecked
  183. 12 => {
  184. #[cfg(feature = "logging")]
  185. pinocchio::msg!("Instruction: TransferChecked");
  186. process_transfer_checked(accounts, instruction_data)
  187. }
  188. // 13 - ApproveChecked
  189. 13 => {
  190. #[cfg(feature = "logging")]
  191. pinocchio::msg!("Instruction: ApproveChecked");
  192. process_approve_checked(accounts, instruction_data)
  193. }
  194. // 14 - MintToChecked
  195. 14 => {
  196. #[cfg(feature = "logging")]
  197. pinocchio::msg!("Instruction: MintToChecked");
  198. process_mint_to_checked(accounts, instruction_data)
  199. }
  200. // 15 - BurnChecked
  201. 15 => {
  202. #[cfg(feature = "logging")]
  203. pinocchio::msg!("Instruction: BurnChecked");
  204. process_burn_checked(accounts, instruction_data)
  205. }
  206. // 17 - SyncNative
  207. 17 => {
  208. #[cfg(feature = "logging")]
  209. pinocchio::msg!("Instruction: SyncNative");
  210. process_sync_native(accounts)
  211. }
  212. // 19 - InitializeMultisig2
  213. 19 => {
  214. #[cfg(feature = "logging")]
  215. pinocchio::msg!("Instruction: InitializeMultisig2");
  216. process_initialize_multisig2(accounts, instruction_data)
  217. }
  218. // 21 - GetAccountDataSize
  219. 21 => {
  220. #[cfg(feature = "logging")]
  221. pinocchio::msg!("Instruction: GetAccountDataSize");
  222. process_get_account_data_size(accounts)
  223. }
  224. // 22 - InitializeImmutableOwner
  225. 22 => {
  226. #[cfg(feature = "logging")]
  227. pinocchio::msg!("Instruction: InitializeImmutableOwner");
  228. process_initialize_immutable_owner(accounts)
  229. }
  230. // 23 - AmountToUiAmount
  231. 23 => {
  232. #[cfg(feature = "logging")]
  233. pinocchio::msg!("Instruction: AmountToUiAmount");
  234. process_amount_to_ui_amount(accounts, instruction_data)
  235. }
  236. // 24 - UiAmountToAmount
  237. 24 => {
  238. #[cfg(feature = "logging")]
  239. pinocchio::msg!("Instruction: UiAmountToAmount");
  240. process_ui_amount_to_amount(accounts, instruction_data)
  241. }
  242. // 38 - WithdrawExcessLamports
  243. 38 => {
  244. #[cfg(feature = "logging")]
  245. pinocchio::msg!("Instruction: WithdrawExcessLamports");
  246. process_withdraw_excess_lamports(accounts)
  247. }
  248. _ => Err(ProgramError::InvalidInstructionData),
  249. }
  250. }