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