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