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 solana_account_info::{next_account_info, AccountInfo},
12 solana_cpi::set_return_data,
13 solana_msg::msg,
14 solana_program_error::{ProgramError, ProgramResult},
15 solana_program_memory::sol_memcmp,
16 solana_program_option::COption,
17 solana_program_pack::{IsInitialized, Pack},
18 solana_pubkey::{Pubkey, PUBKEY_BYTES},
19 solana_rent::Rent,
20 solana_sdk_ids::system_program,
21 solana_sysvar::Sysvar,
22};
23
24pub struct Processor {}
26impl Processor {
27 fn _process_initialize_mint(
28 accounts: &[AccountInfo],
29 decimals: u8,
30 mint_authority: Pubkey,
31 freeze_authority: COption<Pubkey>,
32 rent_sysvar_account: bool,
33 ) -> ProgramResult {
34 let account_info_iter = &mut accounts.iter();
35 let mint_info = next_account_info(account_info_iter)?;
36 let mint_data_len = mint_info.data_len();
37 let rent = if rent_sysvar_account {
38 Rent::from_account_info(next_account_info(account_info_iter)?)?
39 } else {
40 Rent::get()?
41 };
42
43 let mut mint = Mint::unpack_unchecked(&mint_info.data.borrow())?;
44 if mint.is_initialized {
45 return Err(TokenError::AlreadyInUse.into());
46 }
47
48 if !rent.is_exempt(mint_info.lamports(), mint_data_len) {
49 return Err(TokenError::NotRentExempt.into());
50 }
51
52 mint.mint_authority = COption::Some(mint_authority);
53 mint.decimals = decimals;
54 mint.is_initialized = true;
55 mint.freeze_authority = freeze_authority;
56
57 Mint::pack(mint, &mut mint_info.data.borrow_mut())?;
58
59 Ok(())
60 }
61
62 pub fn process_initialize_mint(
64 accounts: &[AccountInfo],
65 decimals: u8,
66 mint_authority: Pubkey,
67 freeze_authority: COption<Pubkey>,
68 ) -> ProgramResult {
69 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, true)
70 }
71
72 pub fn process_initialize_mint2(
75 accounts: &[AccountInfo],
76 decimals: u8,
77 mint_authority: Pubkey,
78 freeze_authority: COption<Pubkey>,
79 ) -> ProgramResult {
80 Self::_process_initialize_mint(accounts, decimals, mint_authority, freeze_authority, false)
81 }
82
83 fn _process_initialize_account(
84 program_id: &Pubkey,
85 accounts: &[AccountInfo],
86 owner: Option<&Pubkey>,
87 rent_sysvar_account: bool,
88 ) -> ProgramResult {
89 let account_info_iter = &mut accounts.iter();
90 let new_account_info = next_account_info(account_info_iter)?;
91 let mint_info = next_account_info(account_info_iter)?;
92 let owner = if let Some(owner) = owner {
93 owner
94 } else {
95 next_account_info(account_info_iter)?.key
96 };
97 let new_account_info_data_len = new_account_info.data_len();
98 let rent = if rent_sysvar_account {
99 Rent::from_account_info(next_account_info(account_info_iter)?)?
100 } else {
101 Rent::get()?
102 };
103
104 let mut account = Account::unpack_unchecked(&new_account_info.data.borrow())?;
105 if account.is_initialized() {
106 return Err(TokenError::AlreadyInUse.into());
107 }
108
109 if !rent.is_exempt(new_account_info.lamports(), new_account_info_data_len) {
110 return Err(TokenError::NotRentExempt.into());
111 }
112
113 let is_native_mint = Self::cmp_pubkeys(mint_info.key, &crate::native_mint::id());
114 if !is_native_mint {
115 Self::check_account_owner(program_id, mint_info)?;
116 let _ = Mint::unpack(&mint_info.data.borrow_mut())
117 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
118 }
119
120 account.mint = *mint_info.key;
121 account.owner = *owner;
122 account.close_authority = COption::None;
123 account.delegate = COption::None;
124 account.delegated_amount = 0;
125 account.state = AccountState::Initialized;
126 if is_native_mint {
127 let rent_exempt_reserve = rent.minimum_balance(new_account_info_data_len);
128 account.is_native = COption::Some(rent_exempt_reserve);
129 account.amount = new_account_info
130 .lamports()
131 .checked_sub(rent_exempt_reserve)
132 .ok_or(TokenError::Overflow)?;
133 } else {
134 account.is_native = COption::None;
135 account.amount = 0;
136 };
137
138 Account::pack(account, &mut new_account_info.data.borrow_mut())?;
139
140 Ok(())
141 }
142
143 pub fn process_initialize_account(
146 program_id: &Pubkey,
147 accounts: &[AccountInfo],
148 ) -> ProgramResult {
149 Self::_process_initialize_account(program_id, accounts, None, true)
150 }
151
152 pub fn process_initialize_account2(
155 program_id: &Pubkey,
156 accounts: &[AccountInfo],
157 owner: Pubkey,
158 ) -> ProgramResult {
159 Self::_process_initialize_account(program_id, accounts, Some(&owner), true)
160 }
161
162 pub fn process_initialize_account3(
165 program_id: &Pubkey,
166 accounts: &[AccountInfo],
167 owner: Pubkey,
168 ) -> ProgramResult {
169 Self::_process_initialize_account(program_id, accounts, Some(&owner), false)
170 }
171
172 fn _process_initialize_multisig(
173 accounts: &[AccountInfo],
174 m: u8,
175 rent_sysvar_account: bool,
176 ) -> ProgramResult {
177 let account_info_iter = &mut accounts.iter();
178 let multisig_info = next_account_info(account_info_iter)?;
179 let multisig_info_data_len = multisig_info.data_len();
180 let rent = if rent_sysvar_account {
181 Rent::from_account_info(next_account_info(account_info_iter)?)?
182 } else {
183 Rent::get()?
184 };
185
186 let mut multisig = Multisig::unpack_unchecked(&multisig_info.data.borrow())?;
187 if multisig.is_initialized {
188 return Err(TokenError::AlreadyInUse.into());
189 }
190
191 if !rent.is_exempt(multisig_info.lamports(), multisig_info_data_len) {
192 return Err(TokenError::NotRentExempt.into());
193 }
194
195 let signer_infos = account_info_iter.as_slice();
196 multisig.m = m;
197 multisig.n = signer_infos.len() as u8;
198 if !is_valid_signer_index(multisig.n as usize) {
199 return Err(TokenError::InvalidNumberOfProvidedSigners.into());
200 }
201 if !is_valid_signer_index(multisig.m as usize) {
202 return Err(TokenError::InvalidNumberOfRequiredSigners.into());
203 }
204 for (i, signer_info) in signer_infos.iter().enumerate() {
205 multisig.signers[i] = *signer_info.key;
206 }
207 multisig.is_initialized = true;
208
209 Multisig::pack(multisig, &mut multisig_info.data.borrow_mut())?;
210
211 Ok(())
212 }
213
214 pub fn process_initialize_multisig(accounts: &[AccountInfo], m: u8) -> ProgramResult {
217 Self::_process_initialize_multisig(accounts, m, true)
218 }
219
220 pub fn process_initialize_multisig2(accounts: &[AccountInfo], m: u8) -> ProgramResult {
223 Self::_process_initialize_multisig(accounts, m, false)
224 }
225
226 pub fn process_transfer(
228 program_id: &Pubkey,
229 accounts: &[AccountInfo],
230 amount: u64,
231 expected_decimals: Option<u8>,
232 ) -> ProgramResult {
233 let account_info_iter = &mut accounts.iter();
234
235 let source_account_info = next_account_info(account_info_iter)?;
236
237 let expected_mint_info = if let Some(expected_decimals) = expected_decimals {
238 Some((next_account_info(account_info_iter)?, expected_decimals))
239 } else {
240 None
241 };
242
243 let destination_account_info = next_account_info(account_info_iter)?;
244 let authority_info = next_account_info(account_info_iter)?;
245
246 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
247 let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?;
248
249 if source_account.is_frozen() || destination_account.is_frozen() {
250 return Err(TokenError::AccountFrozen.into());
251 }
252 if source_account.amount < amount {
253 return Err(TokenError::InsufficientFunds.into());
254 }
255 if !Self::cmp_pubkeys(&source_account.mint, &destination_account.mint) {
256 return Err(TokenError::MintMismatch.into());
257 }
258
259 if let Some((mint_info, expected_decimals)) = expected_mint_info {
260 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
261 return Err(TokenError::MintMismatch.into());
262 }
263
264 let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
265 if expected_decimals != mint.decimals {
266 return Err(TokenError::MintDecimalsMismatch.into());
267 }
268 }
269
270 let self_transfer =
271 Self::cmp_pubkeys(source_account_info.key, destination_account_info.key);
272
273 match source_account.delegate {
274 COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => {
275 Self::validate_owner(
276 program_id,
277 delegate,
278 authority_info,
279 account_info_iter.as_slice(),
280 )?;
281 if source_account.delegated_amount < amount {
282 return Err(TokenError::InsufficientFunds.into());
283 }
284 if !self_transfer {
285 source_account.delegated_amount = source_account
286 .delegated_amount
287 .checked_sub(amount)
288 .ok_or(TokenError::Overflow)?;
289 if source_account.delegated_amount == 0 {
290 source_account.delegate = COption::None;
291 }
292 }
293 }
294 _ => Self::validate_owner(
295 program_id,
296 &source_account.owner,
297 authority_info,
298 account_info_iter.as_slice(),
299 )?,
300 };
301
302 if self_transfer || amount == 0 {
303 Self::check_account_owner(program_id, source_account_info)?;
304 Self::check_account_owner(program_id, destination_account_info)?;
305 }
306
307 if self_transfer {
310 return Ok(());
311 }
312
313 source_account.amount = source_account
314 .amount
315 .checked_sub(amount)
316 .ok_or(TokenError::Overflow)?;
317 destination_account.amount = destination_account
318 .amount
319 .checked_add(amount)
320 .ok_or(TokenError::Overflow)?;
321
322 if source_account.is_native() {
323 let source_starting_lamports = source_account_info.lamports();
324 **source_account_info.lamports.borrow_mut() = source_starting_lamports
325 .checked_sub(amount)
326 .ok_or(TokenError::Overflow)?;
327
328 let destination_starting_lamports = destination_account_info.lamports();
329 **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
330 .checked_add(amount)
331 .ok_or(TokenError::Overflow)?;
332 }
333
334 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
335 Account::pack(
336 destination_account,
337 &mut destination_account_info.data.borrow_mut(),
338 )?;
339
340 Ok(())
341 }
342
343 pub fn process_approve(
345 program_id: &Pubkey,
346 accounts: &[AccountInfo],
347 amount: u64,
348 expected_decimals: Option<u8>,
349 ) -> ProgramResult {
350 let account_info_iter = &mut accounts.iter();
351
352 let source_account_info = next_account_info(account_info_iter)?;
353
354 let expected_mint_info = if let Some(expected_decimals) = expected_decimals {
355 Some((next_account_info(account_info_iter)?, expected_decimals))
356 } else {
357 None
358 };
359 let delegate_info = next_account_info(account_info_iter)?;
360 let owner_info = next_account_info(account_info_iter)?;
361
362 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
363
364 if source_account.is_frozen() {
365 return Err(TokenError::AccountFrozen.into());
366 }
367
368 if let Some((mint_info, expected_decimals)) = expected_mint_info {
369 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
370 return Err(TokenError::MintMismatch.into());
371 }
372
373 let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
374 if expected_decimals != mint.decimals {
375 return Err(TokenError::MintDecimalsMismatch.into());
376 }
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::Some(*delegate_info.key);
387 source_account.delegated_amount = amount;
388
389 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
390
391 Ok(())
392 }
393
394 pub fn process_revoke(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
396 let account_info_iter = &mut accounts.iter();
397 let source_account_info = next_account_info(account_info_iter)?;
398
399 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
400
401 let owner_info = next_account_info(account_info_iter)?;
402
403 if source_account.is_frozen() {
404 return Err(TokenError::AccountFrozen.into());
405 }
406
407 Self::validate_owner(
408 program_id,
409 &source_account.owner,
410 owner_info,
411 account_info_iter.as_slice(),
412 )?;
413
414 source_account.delegate = COption::None;
415 source_account.delegated_amount = 0;
416
417 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
418
419 Ok(())
420 }
421
422 pub fn process_set_authority(
424 program_id: &Pubkey,
425 accounts: &[AccountInfo],
426 authority_type: AuthorityType,
427 new_authority: COption<Pubkey>,
428 ) -> ProgramResult {
429 let account_info_iter = &mut accounts.iter();
430 let account_info = next_account_info(account_info_iter)?;
431 let authority_info = next_account_info(account_info_iter)?;
432
433 if account_info.data_len() == Account::get_packed_len() {
434 let mut account = Account::unpack(&account_info.data.borrow())?;
435
436 if account.is_frozen() {
437 return Err(TokenError::AccountFrozen.into());
438 }
439
440 match authority_type {
441 AuthorityType::AccountOwner => {
442 Self::validate_owner(
443 program_id,
444 &account.owner,
445 authority_info,
446 account_info_iter.as_slice(),
447 )?;
448
449 if let COption::Some(authority) = new_authority {
450 account.owner = authority;
451 } else {
452 return Err(TokenError::InvalidInstruction.into());
453 }
454
455 account.delegate = COption::None;
456 account.delegated_amount = 0;
457
458 if account.is_native() {
459 account.close_authority = COption::None;
460 }
461 }
462 AuthorityType::CloseAccount => {
463 let authority = account.close_authority.unwrap_or(account.owner);
464 Self::validate_owner(
465 program_id,
466 &authority,
467 authority_info,
468 account_info_iter.as_slice(),
469 )?;
470 account.close_authority = new_authority;
471 }
472 _ => {
473 return Err(TokenError::AuthorityTypeNotSupported.into());
474 }
475 }
476 Account::pack(account, &mut account_info.data.borrow_mut())?;
477 } else if account_info.data_len() == Mint::get_packed_len() {
478 let mut mint = Mint::unpack(&account_info.data.borrow())?;
479 match authority_type {
480 AuthorityType::MintTokens => {
481 let mint_authority = mint
484 .mint_authority
485 .ok_or(Into::<ProgramError>::into(TokenError::FixedSupply))?;
486 Self::validate_owner(
487 program_id,
488 &mint_authority,
489 authority_info,
490 account_info_iter.as_slice(),
491 )?;
492 mint.mint_authority = new_authority;
493 }
494 AuthorityType::FreezeAccount => {
495 let freeze_authority = mint
498 .freeze_authority
499 .ok_or(Into::<ProgramError>::into(TokenError::MintCannotFreeze))?;
500 Self::validate_owner(
501 program_id,
502 &freeze_authority,
503 authority_info,
504 account_info_iter.as_slice(),
505 )?;
506 mint.freeze_authority = new_authority;
507 }
508 _ => {
509 return Err(TokenError::AuthorityTypeNotSupported.into());
510 }
511 }
512 Mint::pack(mint, &mut account_info.data.borrow_mut())?;
513 } else {
514 return Err(ProgramError::InvalidArgument);
515 }
516
517 Ok(())
518 }
519
520 pub fn process_mint_to(
522 program_id: &Pubkey,
523 accounts: &[AccountInfo],
524 amount: u64,
525 expected_decimals: Option<u8>,
526 ) -> ProgramResult {
527 let account_info_iter = &mut accounts.iter();
528 let mint_info = next_account_info(account_info_iter)?;
529 let destination_account_info = next_account_info(account_info_iter)?;
530 let owner_info = next_account_info(account_info_iter)?;
531
532 let mut destination_account = Account::unpack(&destination_account_info.data.borrow())?;
533 if destination_account.is_frozen() {
534 return Err(TokenError::AccountFrozen.into());
535 }
536
537 if destination_account.is_native() {
538 return Err(TokenError::NativeNotSupported.into());
539 }
540 if !Self::cmp_pubkeys(mint_info.key, &destination_account.mint) {
541 return Err(TokenError::MintMismatch.into());
542 }
543
544 let mut mint = Mint::unpack(&mint_info.data.borrow())?;
545 if let Some(expected_decimals) = expected_decimals {
546 if expected_decimals != mint.decimals {
547 return Err(TokenError::MintDecimalsMismatch.into());
548 }
549 }
550
551 match mint.mint_authority {
552 COption::Some(mint_authority) => Self::validate_owner(
553 program_id,
554 &mint_authority,
555 owner_info,
556 account_info_iter.as_slice(),
557 )?,
558 COption::None => return Err(TokenError::FixedSupply.into()),
559 }
560
561 if amount == 0 {
562 Self::check_account_owner(program_id, mint_info)?;
563 Self::check_account_owner(program_id, destination_account_info)?;
564 }
565
566 destination_account.amount = destination_account
567 .amount
568 .checked_add(amount)
569 .ok_or(TokenError::Overflow)?;
570
571 mint.supply = mint
572 .supply
573 .checked_add(amount)
574 .ok_or(TokenError::Overflow)?;
575
576 Account::pack(
577 destination_account,
578 &mut destination_account_info.data.borrow_mut(),
579 )?;
580 Mint::pack(mint, &mut mint_info.data.borrow_mut())?;
581
582 Ok(())
583 }
584
585 pub fn process_burn(
587 program_id: &Pubkey,
588 accounts: &[AccountInfo],
589 amount: u64,
590 expected_decimals: Option<u8>,
591 ) -> ProgramResult {
592 let account_info_iter = &mut accounts.iter();
593
594 let source_account_info = next_account_info(account_info_iter)?;
595 let mint_info = next_account_info(account_info_iter)?;
596 let authority_info = next_account_info(account_info_iter)?;
597
598 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
599 let mut mint = Mint::unpack(&mint_info.data.borrow())?;
600
601 if source_account.is_frozen() {
602 return Err(TokenError::AccountFrozen.into());
603 }
604 if source_account.is_native() {
605 return Err(TokenError::NativeNotSupported.into());
606 }
607 if source_account.amount < amount {
608 return Err(TokenError::InsufficientFunds.into());
609 }
610 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
611 return Err(TokenError::MintMismatch.into());
612 }
613
614 if let Some(expected_decimals) = expected_decimals {
615 if expected_decimals != mint.decimals {
616 return Err(TokenError::MintDecimalsMismatch.into());
617 }
618 }
619
620 if !source_account.is_owned_by_system_program_or_incinerator() {
621 match source_account.delegate {
622 COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => {
623 Self::validate_owner(
624 program_id,
625 delegate,
626 authority_info,
627 account_info_iter.as_slice(),
628 )?;
629
630 if source_account.delegated_amount < amount {
631 return Err(TokenError::InsufficientFunds.into());
632 }
633 source_account.delegated_amount = source_account
634 .delegated_amount
635 .checked_sub(amount)
636 .ok_or(TokenError::Overflow)?;
637 if source_account.delegated_amount == 0 {
638 source_account.delegate = COption::None;
639 }
640 }
641 _ => Self::validate_owner(
642 program_id,
643 &source_account.owner,
644 authority_info,
645 account_info_iter.as_slice(),
646 )?,
647 }
648 }
649
650 if amount == 0 {
651 Self::check_account_owner(program_id, source_account_info)?;
652 Self::check_account_owner(program_id, mint_info)?;
653 }
654
655 source_account.amount = source_account
656 .amount
657 .checked_sub(amount)
658 .ok_or(TokenError::Overflow)?;
659 mint.supply = mint
660 .supply
661 .checked_sub(amount)
662 .ok_or(TokenError::Overflow)?;
663
664 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
665 Mint::pack(mint, &mut mint_info.data.borrow_mut())?;
666
667 Ok(())
668 }
669
670 pub fn process_close_account(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
672 let account_info_iter = &mut accounts.iter();
673 let source_account_info = next_account_info(account_info_iter)?;
674 let destination_account_info = next_account_info(account_info_iter)?;
675 let authority_info = next_account_info(account_info_iter)?;
676
677 if Self::cmp_pubkeys(source_account_info.key, destination_account_info.key) {
678 return Err(ProgramError::InvalidAccountData);
679 }
680
681 let source_account = Account::unpack(&source_account_info.data.borrow())?;
682 if !source_account.is_native() && source_account.amount != 0 {
683 return Err(TokenError::NonNativeHasBalance.into());
684 }
685
686 let authority = source_account
687 .close_authority
688 .unwrap_or(source_account.owner);
689 if !source_account.is_owned_by_system_program_or_incinerator() {
690 Self::validate_owner(
691 program_id,
692 &authority,
693 authority_info,
694 account_info_iter.as_slice(),
695 )?;
696 } else if !solana_sdk_ids::incinerator::check_id(destination_account_info.key) {
697 return Err(ProgramError::InvalidAccountData);
698 }
699
700 let destination_starting_lamports = destination_account_info.lamports();
701 **destination_account_info.lamports.borrow_mut() = destination_starting_lamports
702 .checked_add(source_account_info.lamports())
703 .ok_or(TokenError::Overflow)?;
704
705 **source_account_info.lamports.borrow_mut() = 0;
706 delete_account(source_account_info)?;
707
708 Ok(())
709 }
710
711 pub fn process_toggle_freeze_account(
714 program_id: &Pubkey,
715 accounts: &[AccountInfo],
716 freeze: bool,
717 ) -> ProgramResult {
718 let account_info_iter = &mut accounts.iter();
719 let source_account_info = next_account_info(account_info_iter)?;
720 let mint_info = next_account_info(account_info_iter)?;
721 let authority_info = next_account_info(account_info_iter)?;
722
723 let mut source_account = Account::unpack(&source_account_info.data.borrow())?;
724 if freeze && source_account.is_frozen() || !freeze && !source_account.is_frozen() {
725 return Err(TokenError::InvalidState.into());
726 }
727 if source_account.is_native() {
728 return Err(TokenError::NativeNotSupported.into());
729 }
730 if !Self::cmp_pubkeys(mint_info.key, &source_account.mint) {
731 return Err(TokenError::MintMismatch.into());
732 }
733
734 let mint = Mint::unpack(&mint_info.data.borrow_mut())?;
735 match mint.freeze_authority {
736 COption::Some(authority) => Self::validate_owner(
737 program_id,
738 &authority,
739 authority_info,
740 account_info_iter.as_slice(),
741 ),
742 COption::None => Err(TokenError::MintCannotFreeze.into()),
743 }?;
744
745 source_account.state = if freeze {
746 AccountState::Frozen
747 } else {
748 AccountState::Initialized
749 };
750
751 Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
752
753 Ok(())
754 }
755
756 pub fn process_sync_native(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
758 let account_info_iter = &mut accounts.iter();
759 let native_account_info = next_account_info(account_info_iter)?;
760 Self::check_account_owner(program_id, native_account_info)?;
761
762 let mut native_account = Account::unpack(&native_account_info.data.borrow())?;
763
764 if let COption::Some(rent_exempt_reserve) = native_account.is_native {
765 let new_amount = native_account_info
766 .lamports()
767 .checked_sub(rent_exempt_reserve)
768 .ok_or(TokenError::Overflow)?;
769 if new_amount < native_account.amount {
770 return Err(TokenError::InvalidState.into());
771 }
772 native_account.amount = new_amount;
773 } else {
774 return Err(TokenError::NonNativeNotSupported.into());
775 }
776
777 Account::pack(native_account, &mut native_account_info.data.borrow_mut())?;
778 Ok(())
779 }
780
781 pub fn process_get_account_data_size(
784 program_id: &Pubkey,
785 accounts: &[AccountInfo],
786 ) -> ProgramResult {
787 let account_info_iter = &mut accounts.iter();
788 let mint_info = next_account_info(account_info_iter)?;
790 Self::check_account_owner(program_id, mint_info)?;
791 let _ = Mint::unpack(&mint_info.data.borrow())
792 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
793 set_return_data(&Account::LEN.to_le_bytes());
794 Ok(())
795 }
796
797 pub fn process_initialize_immutable_owner(accounts: &[AccountInfo]) -> ProgramResult {
800 let account_info_iter = &mut accounts.iter();
801 let token_account_info = next_account_info(account_info_iter)?;
802 let account = Account::unpack_unchecked(&token_account_info.data.borrow())?;
803 if account.is_initialized() {
804 return Err(TokenError::AlreadyInUse.into());
805 }
806 msg!("Please upgrade to SPL Token 2022 for immutable owner support");
807 Ok(())
808 }
809
810 pub fn process_amount_to_ui_amount(
813 program_id: &Pubkey,
814 accounts: &[AccountInfo],
815 amount: u64,
816 ) -> ProgramResult {
817 let account_info_iter = &mut accounts.iter();
818 let mint_info = next_account_info(account_info_iter)?;
819 Self::check_account_owner(program_id, mint_info)?;
820
821 let mint = Mint::unpack(&mint_info.data.borrow_mut())
822 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
823 let ui_amount = amount_to_ui_amount_string_trimmed(amount, mint.decimals);
824
825 set_return_data(&ui_amount.into_bytes());
826 Ok(())
827 }
828
829 pub fn process_ui_amount_to_amount(
832 program_id: &Pubkey,
833 accounts: &[AccountInfo],
834 ui_amount: &str,
835 ) -> ProgramResult {
836 let account_info_iter = &mut accounts.iter();
837 let mint_info = next_account_info(account_info_iter)?;
838 Self::check_account_owner(program_id, mint_info)?;
839
840 let mint = Mint::unpack(&mint_info.data.borrow_mut())
841 .map_err(|_| Into::<ProgramError>::into(TokenError::InvalidMint))?;
842 let amount = try_ui_amount_into_amount(ui_amount.to_string(), mint.decimals)?;
843
844 set_return_data(&amount.to_le_bytes());
845 Ok(())
846 }
847
848 pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
850 let instruction = TokenInstruction::unpack(input)?;
851
852 match instruction {
853 TokenInstruction::InitializeMint {
854 decimals,
855 mint_authority,
856 freeze_authority,
857 } => {
858 msg!("Instruction: InitializeMint");
859 Self::process_initialize_mint(accounts, decimals, mint_authority, freeze_authority)
860 }
861 TokenInstruction::InitializeMint2 {
862 decimals,
863 mint_authority,
864 freeze_authority,
865 } => {
866 msg!("Instruction: InitializeMint2");
867 Self::process_initialize_mint2(accounts, decimals, mint_authority, freeze_authority)
868 }
869 TokenInstruction::InitializeAccount => {
870 msg!("Instruction: InitializeAccount");
871 Self::process_initialize_account(program_id, accounts)
872 }
873 TokenInstruction::InitializeAccount2 { owner } => {
874 msg!("Instruction: InitializeAccount2");
875 Self::process_initialize_account2(program_id, accounts, owner)
876 }
877 TokenInstruction::InitializeAccount3 { owner } => {
878 msg!("Instruction: InitializeAccount3");
879 Self::process_initialize_account3(program_id, accounts, owner)
880 }
881 TokenInstruction::InitializeMultisig { m } => {
882 msg!("Instruction: InitializeMultisig");
883 Self::process_initialize_multisig(accounts, m)
884 }
885 TokenInstruction::InitializeMultisig2 { m } => {
886 msg!("Instruction: InitializeMultisig2");
887 Self::process_initialize_multisig2(accounts, m)
888 }
889 TokenInstruction::Transfer { amount } => {
890 msg!("Instruction: Transfer");
891 Self::process_transfer(program_id, accounts, amount, None)
892 }
893 TokenInstruction::Approve { amount } => {
894 msg!("Instruction: Approve");
895 Self::process_approve(program_id, accounts, amount, None)
896 }
897 TokenInstruction::Revoke => {
898 msg!("Instruction: Revoke");
899 Self::process_revoke(program_id, accounts)
900 }
901 TokenInstruction::SetAuthority {
902 authority_type,
903 new_authority,
904 } => {
905 msg!("Instruction: SetAuthority");
906 Self::process_set_authority(program_id, accounts, authority_type, new_authority)
907 }
908 TokenInstruction::MintTo { amount } => {
909 msg!("Instruction: MintTo");
910 Self::process_mint_to(program_id, accounts, amount, None)
911 }
912 TokenInstruction::Burn { amount } => {
913 msg!("Instruction: Burn");
914 Self::process_burn(program_id, accounts, amount, None)
915 }
916 TokenInstruction::CloseAccount => {
917 msg!("Instruction: CloseAccount");
918 Self::process_close_account(program_id, accounts)
919 }
920 TokenInstruction::FreezeAccount => {
921 msg!("Instruction: FreezeAccount");
922 Self::process_toggle_freeze_account(program_id, accounts, true)
923 }
924 TokenInstruction::ThawAccount => {
925 msg!("Instruction: ThawAccount");
926 Self::process_toggle_freeze_account(program_id, accounts, false)
927 }
928 TokenInstruction::TransferChecked { amount, decimals } => {
929 msg!("Instruction: TransferChecked");
930 Self::process_transfer(program_id, accounts, amount, Some(decimals))
931 }
932 TokenInstruction::ApproveChecked { amount, decimals } => {
933 msg!("Instruction: ApproveChecked");
934 Self::process_approve(program_id, accounts, amount, Some(decimals))
935 }
936 TokenInstruction::MintToChecked { amount, decimals } => {
937 msg!("Instruction: MintToChecked");
938 Self::process_mint_to(program_id, accounts, amount, Some(decimals))
939 }
940 TokenInstruction::BurnChecked { amount, decimals } => {
941 msg!("Instruction: BurnChecked");
942 Self::process_burn(program_id, accounts, amount, Some(decimals))
943 }
944 TokenInstruction::SyncNative => {
945 msg!("Instruction: SyncNative");
946 Self::process_sync_native(program_id, accounts)
947 }
948 TokenInstruction::GetAccountDataSize => {
949 msg!("Instruction: GetAccountDataSize");
950 Self::process_get_account_data_size(program_id, accounts)
951 }
952 TokenInstruction::InitializeImmutableOwner => {
953 msg!("Instruction: InitializeImmutableOwner");
954 Self::process_initialize_immutable_owner(accounts)
955 }
956 TokenInstruction::AmountToUiAmount { amount } => {
957 msg!("Instruction: AmountToUiAmount");
958 Self::process_amount_to_ui_amount(program_id, accounts, amount)
959 }
960 TokenInstruction::UiAmountToAmount { ui_amount } => {
961 msg!("Instruction: UiAmountToAmount");
962 Self::process_ui_amount_to_amount(program_id, accounts, ui_amount)
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(&system_program::id());
1026 let mut account_data = account_info.data.borrow_mut();
1027 let data_len = account_data.len();
1028 solana_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(&system_program::id());
1036 account_info.realloc(0, false)
1037}
1038
1039#[cfg(test)]
1040mod tests {
1041 use {
1042 super::*,
1043 solana_clock::Epoch,
1044 solana_program_error::PrintProgramError,
1045 std::sync::{Arc, RwLock},
1046 };
1047
1048 lazy_static::lazy_static! {
1049 static ref EXPECTED_DATA: Arc<RwLock<Vec<u8>>> = Arc::new(RwLock::new(Vec::new()));
1050 }
1051
1052 fn return_token_error_as_program_error() -> ProgramError {
1053 TokenError::MintMismatch.into()
1054 }
1055
1056 #[test]
1057 fn test_print_error() {
1058 let error = return_token_error_as_program_error();
1059 error.print::<TokenError>();
1060 }
1061
1062 #[test]
1063 fn test_error_as_custom() {
1064 assert_eq!(
1065 return_token_error_as_program_error(),
1066 ProgramError::Custom(3)
1067 );
1068 }
1069
1070 #[test]
1071 fn test_unique_account_sizes() {
1072 assert_ne!(Mint::get_packed_len(), 0);
1073 assert_ne!(Mint::get_packed_len(), Account::get_packed_len());
1074 assert_ne!(Mint::get_packed_len(), Multisig::get_packed_len());
1075 assert_ne!(Account::get_packed_len(), 0);
1076 assert_ne!(Account::get_packed_len(), Multisig::get_packed_len());
1077 assert_ne!(Multisig::get_packed_len(), 0);
1078 }
1079
1080 #[test]
1081 fn test_pack_unpack() {
1082 let check = Mint {
1084 mint_authority: COption::Some(Pubkey::new_from_array([1; 32])),
1085 supply: 42,
1086 decimals: 7,
1087 is_initialized: true,
1088 freeze_authority: COption::Some(Pubkey::new_from_array([2; 32])),
1089 };
1090 let mut packed = vec![0; Mint::get_packed_len() + 1];
1091 assert_eq!(
1092 Err(ProgramError::InvalidAccountData),
1093 Mint::pack(check, &mut packed)
1094 );
1095 let mut packed = vec![0; Mint::get_packed_len() - 1];
1096 assert_eq!(
1097 Err(ProgramError::InvalidAccountData),
1098 Mint::pack(check, &mut packed)
1099 );
1100 let mut packed = vec![0; Mint::get_packed_len()];
1101 Mint::pack(check, &mut packed).unwrap();
1102 let expect = vec![
1103 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1104 1, 1, 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
1105 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1106 ];
1107 assert_eq!(packed, expect);
1108 let unpacked = Mint::unpack(&packed).unwrap();
1109 assert_eq!(unpacked, check);
1110
1111 let check = Account {
1113 mint: Pubkey::new_from_array([1; 32]),
1114 owner: Pubkey::new_from_array([2; 32]),
1115 amount: 3,
1116 delegate: COption::Some(Pubkey::new_from_array([4; 32])),
1117 state: AccountState::Frozen,
1118 is_native: COption::Some(5),
1119 delegated_amount: 6,
1120 close_authority: COption::Some(Pubkey::new_from_array([7; 32])),
1121 };
1122 let mut packed = vec![0; Account::get_packed_len() + 1];
1123 assert_eq!(
1124 Err(ProgramError::InvalidAccountData),
1125 Account::pack(check, &mut packed)
1126 );
1127 let mut packed = vec![0; Account::get_packed_len() - 1];
1128 assert_eq!(
1129 Err(ProgramError::InvalidAccountData),
1130 Account::pack(check, &mut packed)
1131 );
1132 let mut packed = vec![0; Account::get_packed_len()];
1133 Account::pack(check, &mut packed).unwrap();
1134 let expect = vec![
1135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1136 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1137 2, 2, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
1138 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 0, 0, 5, 0, 0,
1139 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1140 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1141 ];
1142 assert_eq!(packed, expect);
1143 let unpacked = Account::unpack(&packed).unwrap();
1144 assert_eq!(unpacked, check);
1145
1146 let check = Multisig {
1148 m: 1,
1149 n: 2,
1150 is_initialized: true,
1151 signers: [Pubkey::new_from_array([3; 32]); MAX_SIGNERS],
1152 };
1153 let mut packed = vec![0; Multisig::get_packed_len() + 1];
1154 assert_eq!(
1155 Err(ProgramError::InvalidAccountData),
1156 Multisig::pack(check, &mut packed)
1157 );
1158 let mut packed = vec![0; Multisig::get_packed_len() - 1];
1159 assert_eq!(
1160 Err(ProgramError::InvalidAccountData),
1161 Multisig::pack(check, &mut packed)
1162 );
1163 let mut packed = vec![0; Multisig::get_packed_len()];
1164 Multisig::pack(check, &mut packed).unwrap();
1165 let expect = vec![
1166 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1167 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1168 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1169 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1170 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1171 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1172 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1173 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1174 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1175 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1176 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1177 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1178 3, 3, 3, 3, 3, 3, 3,
1179 ];
1180 assert_eq!(packed, expect);
1181 let unpacked = Multisig::unpack(&packed).unwrap();
1182 assert_eq!(unpacked, check);
1183 }
1184
1185 #[test]
1186 fn test_validate_owner() {
1187 let program_id = crate::id();
1188 let owner_key = Pubkey::new_unique();
1189 let mut signer_keys = [Pubkey::default(); MAX_SIGNERS];
1190 for signer_key in signer_keys.iter_mut().take(MAX_SIGNERS) {
1191 *signer_key = Pubkey::new_unique();
1192 }
1193 let mut signer_lamports = 0;
1194 let mut signer_data = vec![];
1195 let mut signers = vec![
1196 AccountInfo::new(
1197 &owner_key,
1198 true,
1199 false,
1200 &mut signer_lamports,
1201 &mut signer_data,
1202 &program_id,
1203 false,
1204 Epoch::default(),
1205 );
1206 MAX_SIGNERS + 1
1207 ];
1208 for (signer, key) in signers.iter_mut().zip(&signer_keys) {
1209 signer.key = key;
1210 }
1211 let mut lamports = 0;
1212 let mut data = vec![0; Multisig::get_packed_len()];
1213 let mut multisig = Multisig::unpack_unchecked(&data).unwrap();
1214 multisig.m = MAX_SIGNERS as u8;
1215 multisig.n = MAX_SIGNERS as u8;
1216 multisig.signers = signer_keys;
1217 multisig.is_initialized = true;
1218 Multisig::pack(multisig, &mut data).unwrap();
1219 let owner_account_info = AccountInfo::new(
1220 &owner_key,
1221 false,
1222 false,
1223 &mut lamports,
1224 &mut data,
1225 &program_id,
1226 false,
1227 Epoch::default(),
1228 );
1229
1230 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap();
1232
1233 {
1235 let mut multisig =
1236 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1237 multisig.m = 1;
1238 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1239 }
1240 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap();
1241
1242 {
1244 let mut multisig =
1245 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1246 multisig.m = 2;
1247 multisig.n = 1;
1248 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1249 }
1250 assert_eq!(
1251 Err(ProgramError::MissingRequiredSignature),
1252 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers)
1253 );
1254
1255 {
1257 let mut multisig =
1258 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1259 multisig.m = 0;
1260 multisig.n = 11;
1261 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1262 }
1263 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers).unwrap();
1264
1265 {
1267 let mut multisig =
1268 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1269 multisig.m = 2;
1270 multisig.n = 11;
1271 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1272 }
1273 assert_eq!(
1274 Err(ProgramError::MissingRequiredSignature),
1275 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &[])
1276 );
1277 {
1279 let mut multisig =
1280 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1281 multisig.m = 2;
1282 multisig.n = 11;
1283 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1284 }
1285 assert_eq!(
1286 Err(ProgramError::MissingRequiredSignature),
1287 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[0..1])
1288 );
1289
1290 {
1292 let mut multisig =
1293 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1294 multisig.m = 2;
1295 multisig.n = 11;
1296 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1297 }
1298 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers[5..7])
1299 .unwrap();
1300
1301 {
1303 let mut multisig =
1304 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1305 multisig.m = 11;
1306 multisig.n = 11;
1307 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1308 }
1309 signers[5].is_signer = false;
1310 assert_eq!(
1311 Err(ProgramError::MissingRequiredSignature),
1312 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers)
1313 );
1314 signers[5].is_signer = true;
1315
1316 {
1318 let mut signer_lamports = 0;
1319 let mut signer_data = vec![];
1320 let signers = vec![
1321 AccountInfo::new(
1322 &signer_keys[5],
1323 true,
1324 false,
1325 &mut signer_lamports,
1326 &mut signer_data,
1327 &program_id,
1328 false,
1329 Epoch::default(),
1330 );
1331 MAX_SIGNERS + 1
1332 ];
1333 let mut multisig =
1334 Multisig::unpack_unchecked(&owner_account_info.data.borrow()).unwrap();
1335 multisig.m = 11;
1336 multisig.n = 11;
1337 Multisig::pack(multisig, &mut owner_account_info.data.borrow_mut()).unwrap();
1338 assert_eq!(
1339 Err(ProgramError::MissingRequiredSignature),
1340 Processor::validate_owner(&program_id, &owner_key, &owner_account_info, &signers)
1341 );
1342 }
1343 }
1344}