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