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