1use {
4 crate::{
5 amount_to_ui_amount_string_trimmed,
6 error::TokenError,
7 instruction::{is_valid_signer_index, AuthorityType, TokenInstruction, MAX_SIGNERS},
8 state::{Account, AccountState, Mint, Multisig},
9 try_ui_amount_into_amount,
10 },
11 arch_program::{
12 account::{next_account_info, AccountInfo},
13 entrypoint::ProgramResult,
14 input_to_sign::InputToSign,
15 msg,
16 program::{set_input_to_sign, set_return_data},
17 program_error::ProgramError,
18 program_memory::sol_memcmp,
19 program_option::COption,
20 program_pack::{IsInitialized, Pack},
21 pubkey::{Pubkey, PUBKEY_BYTES},
22 system_program::SYSTEM_PROGRAM_ID,
23 },
24};
25
26pub struct Processor {}
28impl Processor {
29 fn _process_initialize_mint(
30 accounts: &[AccountInfo],
31 decimals: u8,
32 mint_authority: Pubkey,
33 freeze_authority: COption<Pubkey>,
34 ) -> ProgramResult {
35 let account_info_iter = &mut accounts.iter();
36 let mint_info = next_account_info(account_info_iter)?;
37
38 let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow())?;
39 if mint.is_initialized {
40 return Err(TokenError::AlreadyInUse.into());
41 }
42
43 mint.mint_authority = COption::Some(mint_authority);
44 mint.decimals = decimals;
45 mint.is_initialized = true;
46 mint.freeze_authority = freeze_authority;
47
48 Mint::pack(mint, &mut mint_info.data.borrow_mut())?;
49
50 Ok(())
51 }
52
53 pub fn process_initialize_mint(
55 accounts: &[AccountInfo],
56 decimals: u8,
57 mint_authority: Pubkey,
58 freeze_authority: COption<Pubkey>,
59 ) -> ProgramResult {
60 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority)
61 }
62
63 pub fn process_initialize_mint2(
66 accounts: &[AccountInfo],
67 decimals: u8,
68 mint_authority: Pubkey,
69 freeze_authority: COption<Pubkey>,
70 ) -> ProgramResult {
71 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority)
72 }
73
74 fn _process_initialize_account(
75 program_id: &Pubkey,
76 accounts: &[AccountInfo],
77 owner: Option<&Pubkey>,
78 ) -> ProgramResult {
79 let account_info_iter = &mut accounts.iter();
80 let new_account_info = next_account_info(account_info_iter)?;
81 let mint_info = next_account_info(account_info_iter)?;
82 let owner = if let Some(owner) = owner {
83 owner
84 } else {
85 next_account_info(account_info_iter)?.key
86 };
87
88 let mut account = Account::unpack_unchecked(&new_account_info.data.borrow())?;
89 if account.is_initialized() {
90 return Err(TokenError::AlreadyInUse.into());
91 }
92
93 Self::check_account_owner(program_id, mint_info)?;
94 let _ = Mint::unpack(&mint_info.data.borrow_mut())
95 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
96
97 account.mint = *mint_info.key;
98 account.owner = *owner;
99 account.close_authority = COption::None;
100 account.delegate = COption::None;
101 account.delegated_amount = 0;
102 account.state = AccountState::Initialized;
103
104 Account::pack(account, &mut new_account_info.data.borrow_mut())?;
105
106 Ok(())
107 }
108
109 pub fn process_initialize_account(
112 program_id: &Pubkey,
113 accounts: &[AccountInfo],
114 ) -> ProgramResult {
115 Self::_process_initialize_account(program_id, accounts, None)
116 }
117
118 pub fn process_initialize_account2(
121 program_id: &Pubkey,
122 accounts: &[AccountInfo],
123 owner: Pubkey,
124 ) -> ProgramResult {
125 Self::_process_initialize_account(program_id, accounts, Some(&owner))
126 }
127
128 pub fn process_initialize_account3(
131 program_id: &Pubkey,
132 accounts: &[AccountInfo],
133 owner: Pubkey,
134 ) -> ProgramResult {
135 Self::_process_initialize_account(program_id, accounts, Some(&owner))
136 }
137
138 fn _process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult {
139 let account_info_iter = &mut accounts.iter();
140 let multisig_info = next_account_info(account_info_iter)?;
141
142 let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?;
143 if multisig.is_initialized {
144 return Err(TokenError::AlreadyInUse.into());
145 }
146
147 let signer_infos = account_info_iter.as_slice();
148 multisig.m = m;
149 multisig.n = signer_infos.len() as u8;
150 if !is_valid_signer_index(multisig.n as usize) {
151 return Err(TokenError::InvalidNumberOfProvidedSigners.into());
152 }
153 if !is_valid_signer_index(multisig.m as usize) {
154 return Err(TokenError::InvalidNumberOfRequiredSigners.into());
155 }
156 for (i, signer_info) in signer_infos.iter().enumerate() {
157 multisig.signers[i] = *signer_info.key;
158 }
159 multisig.is_initialized = true;
160
161 Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?;
162
163 Ok(())
164 }
165
166 pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult {
169 Self::_process_initialize_multisig(accounts, m)
170 }
171
172 pub fn process_transfer(
174 program_id: &Pubkey,
175 accounts: &[AccountInfo],
176 amount: u64,
177 expected_decimals: Option<u8>,
178 ) -> ProgramResult {
179 let account_info_iter = &mut accounts.iter();
180
181 let source_account_info = next_account_info(account_info_iter)?;
182
183 let expected_mint_info = if let Some(expected_decimals) = expected_decimals {
184 Some((next_account_info(account_info_iter)?, expected_decimals))
185 } else {
186 None
187 };
188
189 let destination_account_info = next_account_info(account_info_iter)?;
190 let authority_info = next_account_info(account_info_iter)?;
191
192 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
193 let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?;
194
195 if source_account.is_frozen() || destination_account.is_frozen() {
196 return Err(TokenError::AccountFrozen.into());
197 }
198 if source_account.amount < amount {
199 return Err(TokenError::InsufficientFunds.into());
200 }
201 if !Self::cmp_pubkeys(&source_account.mint, &destination_account.mint) {
202 return Err(TokenError::MintMismatch.into());
203 }
204
205 if let Some((mint_info, expected_decimals)) = expected_mint_info {
206 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
207 return Err(TokenError::MintMismatch.into());
208 }
209
210 let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
211 if expected_decimals != mint.decimals {
212 return Err(TokenError::MintDecimalsMismatch.into());
213 }
214 }
215
216 let self_transfer =
217 Self::cmp_pubkeys(source_account_info.key, destination_account_info.key);
218
219 match source_account.delegate {
220 COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => {
221 Self::validate_owner(
222 program_id,
223 delegate,
224 authority_info,
225 account_info_iter.as_slice(),
226 )?;
227 if source_account.delegated_amount < amount {
228 return Err(TokenError::InsufficientFunds.into());
229 }
230 if !self_transfer {
231 source_account.delegated_amount = source_account
232 .delegated_amount
233 .checked_sub(amount)
234 .ok_or(TokenError::Overflow)?;
235 if source_account.delegated_amount == 0 {
236 source_account.delegate = COption::None;
237 }
238 }
239 }
240 _ => Self::validate_owner(
241 program_id,
242 &source_account.owner,
243 authority_info,
244 account_info_iter.as_slice(),
245 )?,
246 };
247
248 if self_transfer || amount == 0 {
249 Self::check_account_owner(program_id, source_account_info)?;
250 Self::check_account_owner(program_id, destination_account_info)?;
251 }
252
253 if self_transfer {
256 return Ok(());
257 }
258
259 source_account.amount = source_account
260 .amount
261 .checked_sub(amount)
262 .ok_or(TokenError::Overflow)?;
263 destination_account.amount = destination_account
264 .amount
265 .checked_add(amount)
266 .ok_or(TokenError::Overflow)?;
267
268 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
269 Account::pack(
270 destination_account,
271 &mut destination_account_info.data.borrow_mut(),
272 )?;
273
274 Ok(())
275 }
276
277 pub fn process_approve(
279 program_id: &Pubkey,
280 accounts: &[AccountInfo],
281 amount: u64,
282 expected_decimals: Option<u8>,
283 ) -> ProgramResult {
284 let account_info_iter = &mut accounts.iter();
285
286 let source_account_info = next_account_info(account_info_iter)?;
287
288 let expected_mint_info = if let Some(expected_decimals) = expected_decimals {
289 Some((next_account_info(account_info_iter)?, expected_decimals))
290 } else {
291 None
292 };
293 let delegate_info = next_account_info(account_info_iter)?;
294 let owner_info = next_account_info(account_info_iter)?;
295
296 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
297
298 if source_account.is_frozen() {
299 return Err(TokenError::AccountFrozen.into());
300 }
301
302 if let Some((mint_info, expected_decimals)) = expected_mint_info {
303 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
304 return Err(TokenError::MintMismatch.into());
305 }
306
307 let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
308 if expected_decimals != mint.decimals {
309 return Err(TokenError::MintDecimalsMismatch.into());
310 }
311 }
312
313 Self::validate_owner(
314 program_id,
315 &source_account.owner,
316 owner_info,
317 account_info_iter.as_slice(),
318 )?;
319
320 source_account.delegate = COption::Some(*delegate_info.key);
321 source_account.delegated_amount = amount;
322
323 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
324
325 Ok(())
326 }
327
328 pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
330 let account_info_iter = &mut accounts.iter();
331 let source_account_info = next_account_info(account_info_iter)?;
332
333 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
334
335 let owner_info = next_account_info(account_info_iter)?;
336
337 if source_account.is_frozen() {
338 return Err(TokenError::AccountFrozen.into());
339 }
340
341 Self::validate_owner(
342 program_id,
343 &source_account.owner,
344 owner_info,
345 account_info_iter.as_slice(),
346 )?;
347
348 source_account.delegate = COption::None;
349 source_account.delegated_amount = 0;
350
351 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
352
353 Ok(())
354 }
355
356 pub fn process_set_authority(
358 program_id: &Pubkey,
359 accounts: &[AccountInfo],
360 authority_type: AuthorityType,
361 new_authority: COption<Pubkey>,
362 ) -> ProgramResult {
363 let account_info_iter = &mut accounts.iter();
364 let account_info = next_account_info(account_info_iter)?;
365 let authority_info = next_account_info(account_info_iter)?;
366
367 if account_info.data_len() == Account::get_packed_len() {
368 let mut account = Account::unpack(&account_info.data.borrow())?;
369
370 if account.is_frozen() {
371 return Err(TokenError::AccountFrozen.into());
372 }
373
374 match authority_type {
375 AuthorityType::AccountOwner => {
376 Self::validate_owner(
377 program_id,
378 &account.owner,
379 authority_info,
380 account_info_iter.as_slice(),
381 )?;
382
383 if let COption::Some(authority) = new_authority {
384 account.owner = authority;
385 } else {
386 return Err(TokenError::InvalidInstruction.into());
387 }
388
389 account.delegate = COption::None;
390 account.delegated_amount = 0;
391 }
392 AuthorityType::CloseAccount => {
393 let authority = account.close_authority.unwrap_or(account.owner);
394 Self::validate_owner(
395 program_id,
396 &authority,
397 authority_info,
398 account_info_iter.as_slice(),
399 )?;
400 account.close_authority = new_authority;
401 }
402 _ => {
403 return Err(TokenError::AuthorityTypeNotSupported.into());
404 }
405 }
406 Account::pack(account, &mut account_info.data.borrow_mut())?;
407 } else if account_info.data_len() == Mint::get_packed_len() {
408 let mut mint = Mint::unpack(&account_info.data.borrow())?;
409 match authority_type {
410 AuthorityType::MintTokens => {
411 let mint_authority = mint
414 .mint_authority
415 .ok_or(Into::<ProgramError>::into(TokenError::FixedSupply))?;
416 Self::validate_owner(
417 program_id,
418 &mint_authority,
419 authority_info,
420 account_info_iter.as_slice(),
421 )?;
422 mint.mint_authority = new_authority;
423 }
424 AuthorityType::FreezeAccount => {
425 let freeze_authority = mint
428 .freeze_authority
429 .ok_or(Into::<ProgramError>::into(TokenError::MintCannotFreeze))?;
430 Self::validate_owner(
431 program_id,
432 &freeze_authority,
433 authority_info,
434 account_info_iter.as_slice(),
435 )?;
436 mint.freeze_authority = new_authority;
437 }
438 _ => {
439 return Err(TokenError::AuthorityTypeNotSupported.into());
440 }
441 }
442 Mint::pack(mint, &mut account_info.data.borrow_mut())?;
443 } else {
444 return Err(ProgramError::InvalidArgument);
445 }
446
447 Ok(())
448 }
449
450 pub fn process_mint_to(
452 program_id: &Pubkey,
453 accounts: &[AccountInfo],
454 amount: u64,
455 expected_decimals: Option<u8>,
456 ) -> ProgramResult {
457 let account_info_iter = &mut accounts.iter();
458 let mint_info = next_account_info(account_info_iter)?;
459 let destination_account_info = next_account_info(account_info_iter)?;
460 let owner_info = next_account_info(account_info_iter)?;
461
462 let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?;
463 if destination_account.is_frozen() {
464 return Err(TokenError::AccountFrozen.into());
465 }
466
467 if !Self::cmp_pubkeys(mint_info.key, &destination_account.mint) {
468 return Err(TokenError::MintMismatch.into());
469 }
470
471 let mut mint = Mint::unpack(&mint_info.data.borrow())?;
472 if let Some(expected_decimals) = expected_decimals {
473 if expected_decimals != mint.decimals {
474 return Err(TokenError::MintDecimalsMismatch.into());
475 }
476 }
477
478 match mint.mint_authority {
479 COption::Some(mint_authority) => Self::validate_owner(
480 program_id,
481 &mint_authority,
482 owner_info,
483 account_info_iter.as_slice(),
484 )?,
485 COption::None => return Err(TokenError::FixedSupply.into()),
486 }
487
488 if amount == 0 {
489 Self::check_account_owner(program_id, mint_info)?;
490 Self::check_account_owner(program_id, destination_account_info)?;
491 }
492
493 destination_account.amount = destination_account
494 .amount
495 .checked_add(amount)
496 .ok_or(TokenError::Overflow)?;
497
498 mint.supply = mint
499 .supply
500 .checked_add(amount)
501 .ok_or(TokenError::Overflow)?;
502
503 Account::pack(
504 destination_account,
505 &mut destination_account_info.data.borrow_mut(),
506 )?;
507 Mint::pack(mint, &mut mint_info.data.borrow_mut())?;
508
509 Ok(())
510 }
511
512 pub fn process_burn(
514 program_id: &Pubkey,
515 accounts: &[AccountInfo],
516 amount: u64,
517 expected_decimals: Option<u8>,
518 ) -> ProgramResult {
519 let account_info_iter = &mut accounts.iter();
520
521 let source_account_info = next_account_info(account_info_iter)?;
522 let mint_info = next_account_info(account_info_iter)?;
523 let authority_info = next_account_info(account_info_iter)?;
524
525 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
526 let mut mint = Mint::unpack(&mint_info.data.borrow())?;
527
528 if source_account.is_frozen() {
529 return Err(TokenError::AccountFrozen.into());
530 }
531 if source_account.amount < amount {
532 return Err(TokenError::InsufficientFunds.into());
533 }
534 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
535 return Err(TokenError::MintMismatch.into());
536 }
537
538 if let Some(expected_decimals) = expected_decimals {
539 if expected_decimals != mint.decimals {
540 return Err(TokenError::MintDecimalsMismatch.into());
541 }
542 }
543
544 if source_account.owner != SYSTEM_PROGRAM_ID {
545 match source_account.delegate {
546 COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => {
547 Self::validate_owner(
548 program_id,
549 delegate,
550 authority_info,
551 account_info_iter.as_slice(),
552 )?;
553
554 if source_account.delegated_amount < amount {
555 return Err(TokenError::InsufficientFunds.into());
556 }
557 source_account.delegated_amount = source_account
558 .delegated_amount
559 .checked_sub(amount)
560 .ok_or(TokenError::Overflow)?;
561 if source_account.delegated_amount == 0 {
562 source_account.delegate = COption::None;
563 }
564 }
565 _ => Self::validate_owner(
566 program_id,
567 &source_account.owner,
568 authority_info,
569 account_info_iter.as_slice(),
570 )?,
571 }
572 }
573
574 if amount == 0 {
575 Self::check_account_owner(program_id, source_account_info)?;
576 Self::check_account_owner(program_id, mint_info)?;
577 }
578
579 source_account.amount = source_account
580 .amount
581 .checked_sub(amount)
582 .ok_or(TokenError::Overflow)?;
583 mint.supply = mint
584 .supply
585 .checked_sub(amount)
586 .ok_or(TokenError::Overflow)?;
587
588 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
589 Mint::pack(mint, &mut mint_info.data.borrow_mut())?;
590
591 Ok(())
592 }
593
594 pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
596 let account_info_iter = &mut accounts.iter();
597 let source_account_info = next_account_info(account_info_iter)?;
598 let destination_account_info = next_account_info(account_info_iter)?;
599 let authority_info = next_account_info(account_info_iter)?;
600
601 if Self::cmp_pubkeys(source_account_info.key, destination_account_info.key) {
602 return Err(ProgramError::InvalidAccountData);
603 }
604
605 let source_account = Account::unpack(&source_account_info.data.borrow())?;
606 if source_account.amount != 0 {
607 return Err(TokenError::NonNativeHasBalance.into());
608 }
609
610 let authority = source_account
611 .close_authority
612 .unwrap_or(source_account.owner);
613
614 if source_account.owner != SYSTEM_PROGRAM_ID {
615 Self::validate_owner(
616 program_id,
617 &authority,
618 authority_info,
619 account_info_iter.as_slice(),
620 )?;
621 }
622
623 let destination_starting_lamports = destination_account_info.lamports();
624 **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
625 .checked_add(source_account_info.lamports())
626 .ok_or(TokenError::Overflow)?;
627
628 **source_account_info.lamports.borrow_mut() = 0;
629
630 delete_account(source_account_info)?;
631
632 Ok(())
633 }
634
635 pub fn process_toggle_freeze_account(
638 program_id: &Pubkey,
639 accounts: &[AccountInfo],
640 freeze: bool,
641 ) -> ProgramResult {
642 let account_info_iter = &mut accounts.iter();
643 let source_account_info = next_account_info(account_info_iter)?;
644 let mint_info = next_account_info(account_info_iter)?;
645 let authority_info = next_account_info(account_info_iter)?;
646
647 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
648 if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() {
649 return Err(TokenError::InvalidState.into());
650 }
651 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
652 return Err(TokenError::MintMismatch.into());
653 }
654
655 let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
656 match mint.freeze_authority {
657 COption::Some(authority) => Self::validate_owner(
658 program_id,
659 &authority,
660 authority_info,
661 account_info_iter.as_slice(),
662 ),
663 COption::None => Err(TokenError::MintCannotFreeze.into()),
664 }?;
665
666 source_account.state = if freeze {
667 AccountState::Frozen
668 } else {
669 AccountState::Initialized
670 };
671
672 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
673
674 Ok(())
675 }
676
677 pub fn process_get_account_data_size(
680 program_id: &Pubkey,
681 accounts: &[AccountInfo],
682 ) -> ProgramResult {
683 let account_info_iter = &mut accounts.iter();
684 let mint_info = next_account_info(account_info_iter)?;
686 Self::check_account_owner(program_id, mint_info)?;
687 let _ = Mint::unpack(&mint_info.data.borrow())
688 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
689 set_return_data(&Account::LEN.to_le_bytes());
690 Ok(())
691 }
692
693 pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult {
696 let account_info_iter = &mut accounts.iter();
697 let token_account_info = next_account_info(account_info_iter)?;
698 let account = Account::unpack_unchecked(&token_account_info.data.borrow())?;
699 if account.is_initialized() {
700 return Err(TokenError::AlreadyInUse.into());
701 }
702 msg!("Please upgrade to SPL Token 2022 for immutable owner support");
703 Ok(())
704 }
705
706 pub fn process_amount_to_ui_amount(
709 program_id: &Pubkey,
710 accounts: &[AccountInfo],
711 amount: u64,
712 ) -> ProgramResult {
713 let account_info_iter = &mut accounts.iter();
714 let mint_info = next_account_info(account_info_iter)?;
715 Self::check_account_owner(program_id, mint_info)?;
716
717 let mint = Mint::unpack(&mint_info.data.borrow_mut())
718 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
719 let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals);
720
721 set_return_data(&ui_amount.into_bytes());
722 Ok(())
723 }
724
725 pub fn process_ui_amount_to_amount(
728 program_id: &Pubkey,
729 accounts: &[AccountInfo],
730 ui_amount: &str,
731 ) -> ProgramResult {
732 let account_info_iter = &mut accounts.iter();
733 let mint_info = next_account_info(account_info_iter)?;
734 Self::check_account_owner(program_id, mint_info)?;
735
736 let mint = Mint::unpack(&mint_info.data.borrow_mut())
737 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
738 let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?;
739
740 set_return_data(&amount.to_le_bytes());
741 Ok(())
742 }
743
744 pub fn process_anchor(
746 program_id: &Pubkey,
747 accounts: &[AccountInfo],
748 txid: [u8; 32],
749 input_to_sign: InputToSign,
750 ) -> ProgramResult {
751 let account_info_iter = &mut accounts.iter();
752 let account_info = next_account_info(account_info_iter)?;
753 let owner_info = next_account_info(account_info_iter)?;
754
755 let account = Account::unpack(&account_info.data.borrow())?;
756
757 if account.is_frozen() {
758 return Err(TokenError::AccountFrozen.into());
759 }
760
761 Self::validate_owner(
762 program_id,
763 &account.owner,
764 owner_info,
765 account_info_iter.as_slice(),
766 )?;
767
768 set_input_to_sign(account_info_iter.as_slice(), txid, &[input_to_sign])?;
769
770 Ok(())
771 }
772
773 pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
775 let instruction = TokenInstruction::unpack(input)?;
776
777 match instruction {
778 TokenInstruction::InitializeMint {
779 decimals,
780 mint_authority,
781 freeze_authority,
782 } => {
783 msg!("Instruction: InitializeMint");
784 Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority)
785 }
786 TokenInstruction::InitializeMint2 {
787 decimals,
788 mint_authority,
789 freeze_authority,
790 } => {
791 msg!("Instruction: InitializeMint2");
792 Self::process_initialize_mint2(accounts, decimals, mint_authority, freeze_authority)
793 }
794 TokenInstruction::InitializeAccount => {
795 msg!("Instruction: InitializeAccount");
796 Self::process_initialize_account(program_id, accounts)
797 }
798 TokenInstruction::InitializeAccount2 { owner } => {
799 msg!("Instruction: InitializeAccount2");
800 Self::process_initialize_account2(program_id, accounts, owner)
801 }
802 TokenInstruction::InitializeAccount3 { owner } => {
803 msg!("Instruction: InitializeAccount3");
804 Self::process_initialize_account3(program_id, accounts, owner)
805 }
806 TokenInstruction::InitializeMultisig { m } => {
807 msg!("Instruction: InitializeMultisig");
808 Self::process_initialize_multisig(accounts, m)
809 }
810 TokenInstruction::Transfer { amount } => {
811 msg!("Instruction: Transfer");
812 Self::process_transfer(program_id, accounts, amount, None)
813 }
814 TokenInstruction::Approve { amount } => {
815 msg!("Instruction: Approve");
816 Self::process_approve(program_id, accounts, amount, None)
817 }
818 TokenInstruction::Revoke => {
819 msg!("Instruction: Revoke");
820 Self::process_revoke(program_id, accounts)
821 }
822 TokenInstruction::SetAuthority {
823 authority_type,
824 new_authority,
825 } => {
826 msg!("Instruction: SetAuthority");
827 Self::process_set_authority(program_id, accounts, authority_type, new_authority)
828 }
829 TokenInstruction::MintTo { amount } => {
830 msg!("Instruction: MintTo");
831 Self::process_mint_to(program_id, accounts, amount, None)
832 }
833 TokenInstruction::Burn { amount } => {
834 msg!("Instruction: Burn");
835 Self::process_burn(program_id, accounts, amount, None)
836 }
837 TokenInstruction::CloseAccount => {
838 msg!("Instruction: CloseAccount");
839 Self::process_close_account(program_id, accounts)
840 }
841 TokenInstruction::FreezeAccount => {
842 msg!("Instruction: FreezeAccount");
843 Self::process_toggle_freeze_account(program_id, accounts, true)
844 }
845 TokenInstruction::ThawAccount => {
846 msg!("Instruction: ThawAccount");
847 Self::process_toggle_freeze_account(program_id, accounts, false)
848 }
849 TokenInstruction::TransferChecked { amount, decimals } => {
850 msg!("Instruction: TransferChecked");
851 Self::process_transfer(program_id, accounts, amount, Some(decimals))
852 }
853 TokenInstruction::ApproveChecked { amount, decimals } => {
854 msg!("Instruction: ApproveChecked");
855 Self::process_approve(program_id, accounts, amount, Some(decimals))
856 }
857 TokenInstruction::MintToChecked { amount, decimals } => {
858 msg!("Instruction: MintToChecked");
859 Self::process_mint_to(program_id, accounts, amount, Some(decimals))
860 }
861 TokenInstruction::BurnChecked { amount, decimals } => {
862 msg!("Instruction: BurnChecked");
863 Self::process_burn(program_id, accounts, amount, Some(decimals))
864 }
865 TokenInstruction::GetAccountDataSize => {
866 msg!("Instruction: GetAccountDataSize");
867 Self::process_get_account_data_size(program_id, accounts)
868 }
869 TokenInstruction::InitializeImmutableOwner => {
870 msg!("Instruction: InitializeImmutableOwner");
871 Self::process_initialize_immutable_owner(accounts)
872 }
873 TokenInstruction::AmountToUiAmount { amount } => {
874 msg!("Instruction: AmountToUiAmount");
875 Self::process_amount_to_ui_amount(program_id, accounts, amount)
876 }
877 TokenInstruction::UiAmountToAmount { ui_amount } => {
878 msg!("Instruction: UiAmountToAmount");
879 Self::process_ui_amount_to_amount(program_id, accounts, ui_amount)
880 }
881 TokenInstruction::Anchor {
882 txid,
883 input_to_sign,
884 } => {
885 msg!("Instruction: Anchor");
886 Self::process_anchor(program_id, accounts, txid, input_to_sign)
887 }
888 }
889 }
890
891 pub fn check_account_owner(program_id: &Pubkey, account_info: &AccountInfo) -> ProgramResult {
893 if !Self::cmp_pubkeys(program_id, account_info.owner) {
894 Err(ProgramError::IncorrectProgramId)
895 } else {
896 Ok(())
897 }
898 }
899
900 pub fn cmp_pubkeys(a: &Pubkey, b: &Pubkey) -> bool {
903 sol_memcmp(a.as_ref(), b.as_ref(), PUBKEY_BYTES) == 0
904 }
905
906 pub fn validate_owner(
908 program_id: &Pubkey,
909 expected_owner: &Pubkey,
910 owner_account_info: &AccountInfo,
911 signers: &[AccountInfo],
912 ) -> ProgramResult {
913 if !Self::cmp_pubkeys(expected_owner, owner_account_info.key) {
914 return Err(TokenError::OwnerMismatch.into());
915 }
916 if Self::cmp_pubkeys(program_id, owner_account_info.owner)
917 && owner_account_info.data_len() == Multisig::get_packed_len()
918 {
919 let multisig = Multisig::unpack(&owner_account_info.data.borrow())?;
920 let mut num_signers = 0;
921 let mut matched = [false; MAX_SIGNERS];
922 for signer in signers.iter() {
923 for (position, key) in multisig.signers[0..multisig.n as usize].iter().enumerate() {
924 if Self::cmp_pubkeys(key, signer.key) && !matched[position] {
925 if !signer.is_signer {
926 return Err(ProgramError::MissingRequiredSignature);
927 }
928 matched[position] = true;
929 num_signers += 1;
930 }
931 }
932 }
933 if num_signers < multisig.m {
934 return Err(ProgramError::MissingRequiredSignature);
935 }
936 return Ok(());
937 } else if !owner_account_info.is_signer {
938 return Err(ProgramError::MissingRequiredSignature);
939 }
940 Ok(())
941 }
942}
943
944#[cfg(not(target_os = "solana"))]
948fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> {
949 account_info.assign(&Pubkey::from_slice(b"11111111111111111111111111111111"));
950 let mut account_data = account_info.data.borrow_mut();
951 let data_len = account_data.len();
952 arch_program::program_memory::sol_memset(*account_data, 0, data_len);
953 Ok(())
954}
955
956#[cfg(target_os = "solana")]
958fn delete_account(account_info: &AccountInfo) -> Result<(), ProgramError> {
959 account_info.assign(&Pubkey::system_program());
960 account_info.realloc(0, false)
961}