1use {
2 crate::parse_instruction::{
3 check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
4 },
5 extension::{
6 confidential_mint_burn::*, confidential_transfer::*, confidential_transfer_fee::*,
7 cpi_guard::*, default_account_state::*, group_member_pointer::*, group_pointer::*,
8 interest_bearing_mint::*, memo_transfer::*, metadata_pointer::*, mint_close_authority::*,
9 pausable::*, permanent_delegate::*, reallocate::*, scaled_ui_amount::*, token_group::*,
10 token_metadata::*, transfer_fee::*, transfer_hook::*,
11 },
12 serde_json::{json, Map, Value},
13 solana_account_decoder::{
14 parse_account_data::SplTokenAdditionalDataV2, parse_token::token_amount_to_ui_amount_v3,
15 },
16 solana_message::{compiled_instruction::CompiledInstruction, AccountKeys},
17 spl_token_2022::{
18 extension::ExtensionType,
19 instruction::{AuthorityType, TokenInstruction},
20 solana_program::{program_option::COption, pubkey::Pubkey},
21 },
22 spl_token_group_interface::instruction::TokenGroupInstruction,
23 spl_token_metadata_interface::instruction::TokenMetadataInstruction,
24};
25
26mod extension;
27
28pub fn parse_token(
29 instruction: &CompiledInstruction,
30 account_keys: &AccountKeys,
31) -> Result<ParsedInstructionEnum, ParseInstructionError> {
32 match instruction.accounts.iter().max() {
33 Some(index) if (*index as usize) < account_keys.len() => {}
34 _ => {
35 return Err(ParseInstructionError::InstructionKeyMismatch(
37 ParsableProgram::SplToken,
38 ));
39 }
40 }
41 if let Ok(token_instruction) = TokenInstruction::unpack(&instruction.data) {
42 match token_instruction {
43 TokenInstruction::InitializeMint {
44 decimals,
45 mint_authority,
46 freeze_authority,
47 } => {
48 check_num_token_accounts(&instruction.accounts, 2)?;
49 let mut value = json!({
50 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
51 "decimals": decimals,
52 "mintAuthority": mint_authority.to_string(),
53 "rentSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
54 });
55 let map = value.as_object_mut().unwrap();
56 if let COption::Some(freeze_authority) = freeze_authority {
57 map.insert(
58 "freezeAuthority".to_string(),
59 json!(freeze_authority.to_string()),
60 );
61 }
62 Ok(ParsedInstructionEnum {
63 instruction_type: "initializeMint".to_string(),
64 info: value,
65 })
66 }
67 TokenInstruction::InitializeMint2 {
68 decimals,
69 mint_authority,
70 freeze_authority,
71 } => {
72 check_num_token_accounts(&instruction.accounts, 1)?;
73 let mut value = json!({
74 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
75 "decimals": decimals,
76 "mintAuthority": mint_authority.to_string(),
77 });
78 let map = value.as_object_mut().unwrap();
79 if let COption::Some(freeze_authority) = freeze_authority {
80 map.insert(
81 "freezeAuthority".to_string(),
82 json!(freeze_authority.to_string()),
83 );
84 }
85 Ok(ParsedInstructionEnum {
86 instruction_type: "initializeMint2".to_string(),
87 info: value,
88 })
89 }
90 TokenInstruction::InitializeAccount => {
91 check_num_token_accounts(&instruction.accounts, 4)?;
92 Ok(ParsedInstructionEnum {
93 instruction_type: "initializeAccount".to_string(),
94 info: json!({
95 "account": account_keys[instruction.accounts[0] as usize].to_string(),
96 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
97 "owner": account_keys[instruction.accounts[2] as usize].to_string(),
98 "rentSysvar": account_keys[instruction.accounts[3] as usize].to_string(),
99 }),
100 })
101 }
102 TokenInstruction::InitializeAccount2 { owner } => {
103 check_num_token_accounts(&instruction.accounts, 3)?;
104 Ok(ParsedInstructionEnum {
105 instruction_type: "initializeAccount2".to_string(),
106 info: json!({
107 "account": account_keys[instruction.accounts[0] as usize].to_string(),
108 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
109 "owner": owner.to_string(),
110 "rentSysvar": account_keys[instruction.accounts[2] as usize].to_string(),
111 }),
112 })
113 }
114 TokenInstruction::InitializeAccount3 { owner } => {
115 check_num_token_accounts(&instruction.accounts, 2)?;
116 Ok(ParsedInstructionEnum {
117 instruction_type: "initializeAccount3".to_string(),
118 info: json!({
119 "account": account_keys[instruction.accounts[0] as usize].to_string(),
120 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
121 "owner": owner.to_string(),
122 }),
123 })
124 }
125 TokenInstruction::InitializeMultisig { m } => {
126 check_num_token_accounts(&instruction.accounts, 3)?;
127 let mut signers: Vec<String> = vec![];
128 for i in instruction.accounts[2..].iter() {
129 signers.push(account_keys[*i as usize].to_string());
130 }
131 Ok(ParsedInstructionEnum {
132 instruction_type: "initializeMultisig".to_string(),
133 info: json!({
134 "multisig": account_keys[instruction.accounts[0] as usize].to_string(),
135 "rentSysvar": account_keys[instruction.accounts[1] as usize].to_string(),
136 "signers": signers,
137 "m": m,
138 }),
139 })
140 }
141 TokenInstruction::InitializeMultisig2 { m } => {
142 check_num_token_accounts(&instruction.accounts, 2)?;
143 let mut signers: Vec<String> = vec![];
144 for i in instruction.accounts[1..].iter() {
145 signers.push(account_keys[*i as usize].to_string());
146 }
147 Ok(ParsedInstructionEnum {
148 instruction_type: "initializeMultisig2".to_string(),
149 info: json!({
150 "multisig": account_keys[instruction.accounts[0] as usize].to_string(),
151 "signers": signers,
152 "m": m,
153 }),
154 })
155 }
156 #[allow(deprecated)]
157 TokenInstruction::Transfer { amount } => {
158 check_num_token_accounts(&instruction.accounts, 3)?;
159 let mut value = json!({
160 "source": account_keys[instruction.accounts[0] as usize].to_string(),
161 "destination": account_keys[instruction.accounts[1] as usize].to_string(),
162 "amount": amount.to_string(),
163 });
164 let map = value.as_object_mut().unwrap();
165 parse_signers(
166 map,
167 2,
168 account_keys,
169 &instruction.accounts,
170 "authority",
171 "multisigAuthority",
172 );
173 Ok(ParsedInstructionEnum {
174 instruction_type: "transfer".to_string(),
175 info: value,
176 })
177 }
178 TokenInstruction::Approve { amount } => {
179 check_num_token_accounts(&instruction.accounts, 3)?;
180 let mut value = json!({
181 "source": account_keys[instruction.accounts[0] as usize].to_string(),
182 "delegate": account_keys[instruction.accounts[1] as usize].to_string(),
183 "amount": amount.to_string(),
184 });
185 let map = value.as_object_mut().unwrap();
186 parse_signers(
187 map,
188 2,
189 account_keys,
190 &instruction.accounts,
191 "owner",
192 "multisigOwner",
193 );
194 Ok(ParsedInstructionEnum {
195 instruction_type: "approve".to_string(),
196 info: value,
197 })
198 }
199 TokenInstruction::Revoke => {
200 check_num_token_accounts(&instruction.accounts, 2)?;
201 let mut value = json!({
202 "source": account_keys[instruction.accounts[0] as usize].to_string(),
203 });
204 let map = value.as_object_mut().unwrap();
205 parse_signers(
206 map,
207 1,
208 account_keys,
209 &instruction.accounts,
210 "owner",
211 "multisigOwner",
212 );
213 Ok(ParsedInstructionEnum {
214 instruction_type: "revoke".to_string(),
215 info: value,
216 })
217 }
218 TokenInstruction::SetAuthority {
219 authority_type,
220 new_authority,
221 } => {
222 check_num_token_accounts(&instruction.accounts, 2)?;
223 let owned = match authority_type {
224 AuthorityType::MintTokens
225 | AuthorityType::FreezeAccount
226 | AuthorityType::TransferFeeConfig
227 | AuthorityType::WithheldWithdraw
228 | AuthorityType::CloseMint
229 | AuthorityType::InterestRate
230 | AuthorityType::PermanentDelegate
231 | AuthorityType::ConfidentialTransferMint
232 | AuthorityType::TransferHookProgramId
233 | AuthorityType::ConfidentialTransferFeeConfig
234 | AuthorityType::MetadataPointer
235 | AuthorityType::GroupPointer
236 | AuthorityType::GroupMemberPointer
237 | AuthorityType::ScaledUiAmount
238 | AuthorityType::Pause => "mint",
239 AuthorityType::AccountOwner | AuthorityType::CloseAccount => "account",
240 };
241 let mut value = json!({
242 owned: account_keys[instruction.accounts[0] as usize].to_string(),
243 "authorityType": Into::<UiAuthorityType>::into(authority_type),
244 "newAuthority": map_coption_pubkey(new_authority),
245 });
246 let map = value.as_object_mut().unwrap();
247 parse_signers(
248 map,
249 1,
250 account_keys,
251 &instruction.accounts,
252 "authority",
253 "multisigAuthority",
254 );
255 Ok(ParsedInstructionEnum {
256 instruction_type: "setAuthority".to_string(),
257 info: value,
258 })
259 }
260 TokenInstruction::MintTo { amount } => {
261 check_num_token_accounts(&instruction.accounts, 3)?;
262 let mut value = json!({
263 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
264 "account": account_keys[instruction.accounts[1] as usize].to_string(),
265 "amount": amount.to_string(),
266 });
267 let map = value.as_object_mut().unwrap();
268 parse_signers(
269 map,
270 2,
271 account_keys,
272 &instruction.accounts,
273 "mintAuthority",
274 "multisigMintAuthority",
275 );
276 Ok(ParsedInstructionEnum {
277 instruction_type: "mintTo".to_string(),
278 info: value,
279 })
280 }
281 TokenInstruction::Burn { amount } => {
282 check_num_token_accounts(&instruction.accounts, 3)?;
283 let mut value = json!({
284 "account": account_keys[instruction.accounts[0] as usize].to_string(),
285 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
286 "amount": amount.to_string(),
287 });
288 let map = value.as_object_mut().unwrap();
289 parse_signers(
290 map,
291 2,
292 account_keys,
293 &instruction.accounts,
294 "authority",
295 "multisigAuthority",
296 );
297 Ok(ParsedInstructionEnum {
298 instruction_type: "burn".to_string(),
299 info: value,
300 })
301 }
302 TokenInstruction::CloseAccount => {
303 check_num_token_accounts(&instruction.accounts, 3)?;
304 let mut value = json!({
305 "account": account_keys[instruction.accounts[0] as usize].to_string(),
306 "destination": account_keys[instruction.accounts[1] as usize].to_string(),
307 });
308 let map = value.as_object_mut().unwrap();
309 parse_signers(
310 map,
311 2,
312 account_keys,
313 &instruction.accounts,
314 "owner",
315 "multisigOwner",
316 );
317 Ok(ParsedInstructionEnum {
318 instruction_type: "closeAccount".to_string(),
319 info: value,
320 })
321 }
322 TokenInstruction::FreezeAccount => {
323 check_num_token_accounts(&instruction.accounts, 3)?;
324 let mut value = json!({
325 "account": account_keys[instruction.accounts[0] as usize].to_string(),
326 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
327 });
328 let map = value.as_object_mut().unwrap();
329 parse_signers(
330 map,
331 2,
332 account_keys,
333 &instruction.accounts,
334 "freezeAuthority",
335 "multisigFreezeAuthority",
336 );
337 Ok(ParsedInstructionEnum {
338 instruction_type: "freezeAccount".to_string(),
339 info: value,
340 })
341 }
342 TokenInstruction::ThawAccount => {
343 check_num_token_accounts(&instruction.accounts, 3)?;
344 let mut value = json!({
345 "account": account_keys[instruction.accounts[0] as usize].to_string(),
346 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
347 });
348 let map = value.as_object_mut().unwrap();
349 parse_signers(
350 map,
351 2,
352 account_keys,
353 &instruction.accounts,
354 "freezeAuthority",
355 "multisigFreezeAuthority",
356 );
357 Ok(ParsedInstructionEnum {
358 instruction_type: "thawAccount".to_string(),
359 info: value,
360 })
361 }
362 TokenInstruction::TransferChecked { amount, decimals } => {
363 check_num_token_accounts(&instruction.accounts, 4)?;
364 let additional_data = SplTokenAdditionalDataV2::with_decimals(decimals);
365 let mut value = json!({
366 "source": account_keys[instruction.accounts[0] as usize].to_string(),
367 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
368 "destination": account_keys[instruction.accounts[2] as usize].to_string(),
369 "tokenAmount": token_amount_to_ui_amount_v3(amount, &additional_data),
370 });
371 let map = value.as_object_mut().unwrap();
372 parse_signers(
373 map,
374 3,
375 account_keys,
376 &instruction.accounts,
377 "authority",
378 "multisigAuthority",
379 );
380 Ok(ParsedInstructionEnum {
381 instruction_type: "transferChecked".to_string(),
382 info: value,
383 })
384 }
385 TokenInstruction::ApproveChecked { amount, decimals } => {
386 check_num_token_accounts(&instruction.accounts, 4)?;
387 let additional_data = SplTokenAdditionalDataV2::with_decimals(decimals);
388 let mut value = json!({
389 "source": account_keys[instruction.accounts[0] as usize].to_string(),
390 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
391 "delegate": account_keys[instruction.accounts[2] as usize].to_string(),
392 "tokenAmount": token_amount_to_ui_amount_v3(amount, &additional_data),
393 });
394 let map = value.as_object_mut().unwrap();
395 parse_signers(
396 map,
397 3,
398 account_keys,
399 &instruction.accounts,
400 "owner",
401 "multisigOwner",
402 );
403 Ok(ParsedInstructionEnum {
404 instruction_type: "approveChecked".to_string(),
405 info: value,
406 })
407 }
408 TokenInstruction::MintToChecked { amount, decimals } => {
409 check_num_token_accounts(&instruction.accounts, 3)?;
410 let additional_data = SplTokenAdditionalDataV2::with_decimals(decimals);
411 let mut value = json!({
412 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
413 "account": account_keys[instruction.accounts[1] as usize].to_string(),
414 "tokenAmount": token_amount_to_ui_amount_v3(amount, &additional_data),
415 });
416 let map = value.as_object_mut().unwrap();
417 parse_signers(
418 map,
419 2,
420 account_keys,
421 &instruction.accounts,
422 "mintAuthority",
423 "multisigMintAuthority",
424 );
425 Ok(ParsedInstructionEnum {
426 instruction_type: "mintToChecked".to_string(),
427 info: value,
428 })
429 }
430 TokenInstruction::BurnChecked { amount, decimals } => {
431 check_num_token_accounts(&instruction.accounts, 3)?;
432 let additional_data = SplTokenAdditionalDataV2::with_decimals(decimals);
433 let mut value = json!({
434 "account": account_keys[instruction.accounts[0] as usize].to_string(),
435 "mint": account_keys[instruction.accounts[1] as usize].to_string(),
436 "tokenAmount": token_amount_to_ui_amount_v3(amount, &additional_data),
437 });
438 let map = value.as_object_mut().unwrap();
439 parse_signers(
440 map,
441 2,
442 account_keys,
443 &instruction.accounts,
444 "authority",
445 "multisigAuthority",
446 );
447 Ok(ParsedInstructionEnum {
448 instruction_type: "burnChecked".to_string(),
449 info: value,
450 })
451 }
452 TokenInstruction::SyncNative => {
453 check_num_token_accounts(&instruction.accounts, 1)?;
454 Ok(ParsedInstructionEnum {
455 instruction_type: "syncNative".to_string(),
456 info: json!({
457 "account": account_keys[instruction.accounts[0] as usize].to_string(),
458 }),
459 })
460 }
461 TokenInstruction::GetAccountDataSize { extension_types } => {
462 check_num_token_accounts(&instruction.accounts, 1)?;
463 let mut value = json!({
464 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
465 });
466 let map = value.as_object_mut().unwrap();
467 if !extension_types.is_empty() {
468 map.insert(
469 "extensionTypes".to_string(),
470 json!(extension_types
471 .into_iter()
472 .map(UiExtensionType::from)
473 .collect::<Vec<_>>()),
474 );
475 }
476 Ok(ParsedInstructionEnum {
477 instruction_type: "getAccountDataSize".to_string(),
478 info: value,
479 })
480 }
481 TokenInstruction::InitializeImmutableOwner => {
482 check_num_token_accounts(&instruction.accounts, 1)?;
483 Ok(ParsedInstructionEnum {
484 instruction_type: "initializeImmutableOwner".to_string(),
485 info: json!({
486 "account": account_keys[instruction.accounts[0] as usize].to_string(),
487 }),
488 })
489 }
490 TokenInstruction::AmountToUiAmount { amount } => {
491 check_num_token_accounts(&instruction.accounts, 1)?;
492 Ok(ParsedInstructionEnum {
493 instruction_type: "amountToUiAmount".to_string(),
494 info: json!({
495 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
496 "amount": amount.to_string(),
497 }),
498 })
499 }
500 TokenInstruction::UiAmountToAmount { ui_amount } => {
501 check_num_token_accounts(&instruction.accounts, 1)?;
502 Ok(ParsedInstructionEnum {
503 instruction_type: "uiAmountToAmount".to_string(),
504 info: json!({
505 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
506 "uiAmount": ui_amount,
507 }),
508 })
509 }
510 TokenInstruction::InitializeMintCloseAuthority { close_authority } => {
511 parse_initialize_mint_close_authority_instruction(
512 close_authority,
513 &instruction.accounts,
514 account_keys,
515 )
516 }
517 TokenInstruction::TransferFeeExtension => parse_transfer_fee_instruction(
518 &instruction.data[1..],
519 &instruction.accounts,
520 account_keys,
521 ),
522 TokenInstruction::ConfidentialTransferExtension => {
523 parse_confidential_transfer_instruction(
524 &instruction.data[1..],
525 &instruction.accounts,
526 account_keys,
527 )
528 }
529 TokenInstruction::DefaultAccountStateExtension => {
530 if instruction.data.len() <= 2 {
531 return Err(ParseInstructionError::InstructionNotParsable(
532 ParsableProgram::SplToken,
533 ));
534 }
535 parse_default_account_state_instruction(
536 &instruction.data[1..],
537 &instruction.accounts,
538 account_keys,
539 )
540 }
541 TokenInstruction::Reallocate { extension_types } => {
542 parse_reallocate_instruction(extension_types, &instruction.accounts, account_keys)
543 }
544 TokenInstruction::MemoTransferExtension => {
545 if instruction.data.len() < 2 {
546 return Err(ParseInstructionError::InstructionNotParsable(
547 ParsableProgram::SplToken,
548 ));
549 }
550 parse_memo_transfer_instruction(
551 &instruction.data[1..],
552 &instruction.accounts,
553 account_keys,
554 )
555 }
556 TokenInstruction::CreateNativeMint => {
557 check_num_token_accounts(&instruction.accounts, 3)?;
558 Ok(ParsedInstructionEnum {
559 instruction_type: "createNativeMint".to_string(),
560 info: json!({
561 "payer": account_keys[instruction.accounts[0] as usize].to_string(),
562 "nativeMint": account_keys[instruction.accounts[1] as usize].to_string(),
563 "systemProgram": account_keys[instruction.accounts[2] as usize].to_string(),
564 }),
565 })
566 }
567 TokenInstruction::InitializeNonTransferableMint => {
568 check_num_token_accounts(&instruction.accounts, 1)?;
569 Ok(ParsedInstructionEnum {
570 instruction_type: "initializeNonTransferableMint".to_string(),
571 info: json!({
572 "mint": account_keys[instruction.accounts[0] as usize].to_string(),
573 }),
574 })
575 }
576 TokenInstruction::InterestBearingMintExtension => {
577 if instruction.data.len() < 2 {
578 return Err(ParseInstructionError::InstructionNotParsable(
579 ParsableProgram::SplToken,
580 ));
581 }
582 parse_interest_bearing_mint_instruction(
583 &instruction.data[1..],
584 &instruction.accounts,
585 account_keys,
586 )
587 }
588 TokenInstruction::CpiGuardExtension => {
589 if instruction.data.len() < 2 {
590 return Err(ParseInstructionError::InstructionNotParsable(
591 ParsableProgram::SplToken,
592 ));
593 }
594 parse_cpi_guard_instruction(
595 &instruction.data[1..],
596 &instruction.accounts,
597 account_keys,
598 )
599 }
600 TokenInstruction::InitializePermanentDelegate { delegate } => {
601 parse_initialize_permanent_delegate_instruction(
602 delegate,
603 &instruction.accounts,
604 account_keys,
605 )
606 }
607 TokenInstruction::TransferHookExtension => {
608 if instruction.data.len() < 2 {
609 return Err(ParseInstructionError::InstructionNotParsable(
610 ParsableProgram::SplToken,
611 ));
612 }
613 parse_transfer_hook_instruction(
614 &instruction.data[1..],
615 &instruction.accounts,
616 account_keys,
617 )
618 }
619 TokenInstruction::ConfidentialTransferFeeExtension => {
620 if instruction.data.len() < 2 {
621 return Err(ParseInstructionError::InstructionNotParsable(
622 ParsableProgram::SplToken,
623 ));
624 }
625 parse_confidential_transfer_fee_instruction(
626 &instruction.data[1..],
627 &instruction.accounts,
628 account_keys,
629 )
630 }
631 TokenInstruction::WithdrawExcessLamports => {
632 check_num_token_accounts(&instruction.accounts, 3)?;
633 let mut value = json!({
634 "source": account_keys[instruction.accounts[0] as usize].to_string(),
635 "destination": account_keys[instruction.accounts[1] as usize].to_string(),
636 });
637 let map = value.as_object_mut().unwrap();
638 parse_signers(
639 map,
640 2,
641 account_keys,
642 &instruction.accounts,
643 "authority",
644 "multisigAuthority",
645 );
646 Ok(ParsedInstructionEnum {
647 instruction_type: "withdrawExcessLamports".to_string(),
648 info: value,
649 })
650 }
651 TokenInstruction::MetadataPointerExtension => {
652 if instruction.data.len() < 2 {
653 return Err(ParseInstructionError::InstructionNotParsable(
654 ParsableProgram::SplToken,
655 ));
656 }
657 parse_metadata_pointer_instruction(
658 &instruction.data[1..],
659 &instruction.accounts,
660 account_keys,
661 )
662 }
663 TokenInstruction::GroupPointerExtension => {
664 if instruction.data.len() < 2 {
665 return Err(ParseInstructionError::InstructionNotParsable(
666 ParsableProgram::SplToken,
667 ));
668 }
669 parse_group_pointer_instruction(
670 &instruction.data[1..],
671 &instruction.accounts,
672 account_keys,
673 )
674 }
675 TokenInstruction::GroupMemberPointerExtension => {
676 if instruction.data.len() < 2 {
677 return Err(ParseInstructionError::InstructionNotParsable(
678 ParsableProgram::SplToken,
679 ));
680 }
681 parse_group_member_pointer_instruction(
682 &instruction.data[1..],
683 &instruction.accounts,
684 account_keys,
685 )
686 }
687 TokenInstruction::ConfidentialMintBurnExtension => {
688 parse_confidential_mint_burn_instruction(
689 &instruction.data[1..],
690 &instruction.accounts,
691 account_keys,
692 )
693 }
694 TokenInstruction::ScaledUiAmountExtension => parse_scaled_ui_amount_instruction(
695 &instruction.data[1..],
696 &instruction.accounts,
697 account_keys,
698 ),
699 TokenInstruction::PausableExtension => parse_pausable_instruction(
700 &instruction.data[1..],
701 &instruction.accounts,
702 account_keys,
703 ),
704 }
705 } else if let Ok(token_group_instruction) = TokenGroupInstruction::unpack(&instruction.data) {
706 parse_token_group_instruction(
707 &token_group_instruction,
708 &instruction.accounts,
709 account_keys,
710 )
711 } else if let Ok(token_metadata_instruction) =
712 TokenMetadataInstruction::unpack(&instruction.data)
713 {
714 parse_token_metadata_instruction(
715 &token_metadata_instruction,
716 &instruction.accounts,
717 account_keys,
718 )
719 } else {
720 Err(ParseInstructionError::InstructionNotParsable(
721 ParsableProgram::SplToken,
722 ))
723 }
724}
725
726#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
727#[serde(rename_all = "camelCase")]
728pub enum UiAuthorityType {
729 MintTokens,
730 FreezeAccount,
731 AccountOwner,
732 CloseAccount,
733 TransferFeeConfig,
734 WithheldWithdraw,
735 CloseMint,
736 InterestRate,
737 PermanentDelegate,
738 ConfidentialTransferMint,
739 TransferHookProgramId,
740 ConfidentialTransferFeeConfig,
741 MetadataPointer,
742 GroupPointer,
743 GroupMemberPointer,
744 ScaledUiAmount,
745 Pause,
746}
747
748impl From<AuthorityType> for UiAuthorityType {
749 fn from(authority_type: AuthorityType) -> Self {
750 match authority_type {
751 AuthorityType::MintTokens => UiAuthorityType::MintTokens,
752 AuthorityType::FreezeAccount => UiAuthorityType::FreezeAccount,
753 AuthorityType::AccountOwner => UiAuthorityType::AccountOwner,
754 AuthorityType::CloseAccount => UiAuthorityType::CloseAccount,
755 AuthorityType::TransferFeeConfig => UiAuthorityType::TransferFeeConfig,
756 AuthorityType::WithheldWithdraw => UiAuthorityType::WithheldWithdraw,
757 AuthorityType::CloseMint => UiAuthorityType::CloseMint,
758 AuthorityType::InterestRate => UiAuthorityType::InterestRate,
759 AuthorityType::PermanentDelegate => UiAuthorityType::PermanentDelegate,
760 AuthorityType::ConfidentialTransferMint => UiAuthorityType::ConfidentialTransferMint,
761 AuthorityType::TransferHookProgramId => UiAuthorityType::TransferHookProgramId,
762 AuthorityType::ConfidentialTransferFeeConfig => {
763 UiAuthorityType::ConfidentialTransferFeeConfig
764 }
765 AuthorityType::MetadataPointer => UiAuthorityType::MetadataPointer,
766 AuthorityType::GroupPointer => UiAuthorityType::GroupPointer,
767 AuthorityType::GroupMemberPointer => UiAuthorityType::GroupMemberPointer,
768 AuthorityType::ScaledUiAmount => UiAuthorityType::ScaledUiAmount,
769 AuthorityType::Pause => UiAuthorityType::Pause,
770 }
771 }
772}
773
774#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
775#[serde(rename_all = "camelCase")]
776pub enum UiExtensionType {
777 Uninitialized,
778 TransferFeeConfig,
779 TransferFeeAmount,
780 MintCloseAuthority,
781 ConfidentialTransferMint,
782 ConfidentialTransferAccount,
783 DefaultAccountState,
784 ImmutableOwner,
785 MemoTransfer,
786 NonTransferable,
787 InterestBearingConfig,
788 CpiGuard,
789 PermanentDelegate,
790 NonTransferableAccount,
791 TransferHook,
792 TransferHookAccount,
793 ConfidentialTransferFeeConfig,
794 ConfidentialTransferFeeAmount,
795 MetadataPointer,
796 TokenMetadata,
797 GroupPointer,
798 GroupMemberPointer,
799 TokenGroup,
800 TokenGroupMember,
801 ConfidentialMintBurn,
802 ScaledUiAmount,
803 Pausable,
804 PausableAccount,
805}
806
807impl From<ExtensionType> for UiExtensionType {
808 fn from(extension_type: ExtensionType) -> Self {
809 match extension_type {
810 ExtensionType::Uninitialized => UiExtensionType::Uninitialized,
811 ExtensionType::TransferFeeConfig => UiExtensionType::TransferFeeConfig,
812 ExtensionType::TransferFeeAmount => UiExtensionType::TransferFeeAmount,
813 ExtensionType::MintCloseAuthority => UiExtensionType::MintCloseAuthority,
814 ExtensionType::ConfidentialTransferMint => UiExtensionType::ConfidentialTransferMint,
815 ExtensionType::ConfidentialTransferAccount => {
816 UiExtensionType::ConfidentialTransferAccount
817 }
818 ExtensionType::DefaultAccountState => UiExtensionType::DefaultAccountState,
819 ExtensionType::ImmutableOwner => UiExtensionType::ImmutableOwner,
820 ExtensionType::MemoTransfer => UiExtensionType::MemoTransfer,
821 ExtensionType::NonTransferable => UiExtensionType::NonTransferable,
822 ExtensionType::InterestBearingConfig => UiExtensionType::InterestBearingConfig,
823 ExtensionType::CpiGuard => UiExtensionType::CpiGuard,
824 ExtensionType::PermanentDelegate => UiExtensionType::PermanentDelegate,
825 ExtensionType::NonTransferableAccount => UiExtensionType::NonTransferableAccount,
826 ExtensionType::TransferHook => UiExtensionType::TransferHook,
827 ExtensionType::TransferHookAccount => UiExtensionType::TransferHookAccount,
828 ExtensionType::ConfidentialTransferFeeConfig => {
829 UiExtensionType::ConfidentialTransferFeeConfig
830 }
831 ExtensionType::ConfidentialTransferFeeAmount => {
832 UiExtensionType::ConfidentialTransferFeeAmount
833 }
834 ExtensionType::MetadataPointer => UiExtensionType::MetadataPointer,
835 ExtensionType::TokenMetadata => UiExtensionType::TokenMetadata,
836 ExtensionType::GroupPointer => UiExtensionType::GroupPointer,
837 ExtensionType::GroupMemberPointer => UiExtensionType::GroupMemberPointer,
838 ExtensionType::TokenGroup => UiExtensionType::TokenGroup,
839 ExtensionType::TokenGroupMember => UiExtensionType::TokenGroupMember,
840 ExtensionType::ConfidentialMintBurn => UiExtensionType::ConfidentialMintBurn,
841 ExtensionType::ScaledUiAmount => UiExtensionType::ScaledUiAmount,
842 ExtensionType::Pausable => UiExtensionType::Pausable,
843 ExtensionType::PausableAccount => UiExtensionType::PausableAccount,
844 }
845 }
846}
847
848fn parse_signers(
849 map: &mut Map<String, Value>,
850 last_nonsigner_index: usize,
851 account_keys: &AccountKeys,
852 accounts: &[u8],
853 owner_field_name: &str,
854 multisig_field_name: &str,
855) {
856 if accounts.len() > last_nonsigner_index + 1 {
857 let mut signers: Vec<String> = vec![];
858 for i in accounts[last_nonsigner_index + 1..].iter() {
859 signers.push(account_keys[*i as usize].to_string());
860 }
861 map.insert(
862 multisig_field_name.to_string(),
863 json!(account_keys[accounts[last_nonsigner_index] as usize].to_string()),
864 );
865 map.insert("signers".to_string(), json!(signers));
866 } else {
867 map.insert(
868 owner_field_name.to_string(),
869 json!(account_keys[accounts[last_nonsigner_index] as usize].to_string()),
870 );
871 }
872}
873
874fn check_num_token_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInstructionError> {
875 check_num_accounts(accounts, num, ParsableProgram::SplToken)
876}
877
878fn map_coption_pubkey(pubkey: COption<Pubkey>) -> Option<String> {
879 match pubkey {
880 COption::Some(pubkey) => Some(pubkey.to_string()),
881 COption::None => None,
882 }
883}
884
885#[cfg(test)]
886mod test {
887 use {
888 super::*, solana_message::Message, solana_pubkey::Pubkey, spl_token_2022::instruction::*,
889 std::iter::repeat_with,
890 };
891
892 fn test_parse_token(program_id: &Pubkey) {
893 let mint_pubkey = Pubkey::new_unique();
894 let mint_authority = Pubkey::new_unique();
895 let freeze_authority = Pubkey::new_unique();
896 let rent_sysvar = solana_sdk_ids::sysvar::rent::id();
897
898 let initialize_mint_ix = initialize_mint(
900 program_id,
901 &mint_pubkey,
902 &mint_authority,
903 Some(&freeze_authority),
904 2,
905 )
906 .unwrap();
907 let message = Message::new(&[initialize_mint_ix], None);
908 let compiled_instruction = &message.instructions[0];
909 assert_eq!(
910 parse_token(
911 compiled_instruction,
912 &AccountKeys::new(&message.account_keys, None)
913 )
914 .unwrap(),
915 ParsedInstructionEnum {
916 instruction_type: "initializeMint".to_string(),
917 info: json!({
918 "mint": mint_pubkey.to_string(),
919 "decimals": 2,
920 "mintAuthority": mint_authority.to_string(),
921 "freezeAuthority": freeze_authority.to_string(),
922 "rentSysvar": rent_sysvar.to_string(),
923 })
924 }
925 );
926
927 let initialize_mint_ix =
928 initialize_mint(program_id, &mint_pubkey, &mint_authority, None, 2).unwrap();
929 let message = Message::new(&[initialize_mint_ix], None);
930 let compiled_instruction = &message.instructions[0];
931 assert_eq!(
932 parse_token(
933 compiled_instruction,
934 &AccountKeys::new(&message.account_keys, None)
935 )
936 .unwrap(),
937 ParsedInstructionEnum {
938 instruction_type: "initializeMint".to_string(),
939 info: json!({
940 "mint": mint_pubkey.to_string(),
941 "decimals": 2,
942 "mintAuthority": mint_authority.to_string(),
943 "rentSysvar": rent_sysvar.to_string(),
944 })
945 }
946 );
947
948 let initialize_mint_ix = initialize_mint2(
950 program_id,
951 &mint_pubkey,
952 &mint_authority,
953 Some(&freeze_authority),
954 2,
955 )
956 .unwrap();
957 let message = Message::new(&[initialize_mint_ix], None);
958 let compiled_instruction = &message.instructions[0];
959 assert_eq!(
960 parse_token(
961 compiled_instruction,
962 &AccountKeys::new(&message.account_keys, None)
963 )
964 .unwrap(),
965 ParsedInstructionEnum {
966 instruction_type: "initializeMint2".to_string(),
967 info: json!({
968 "mint": mint_pubkey.to_string(),
969 "decimals": 2,
970 "mintAuthority": mint_authority.to_string(),
971 "freezeAuthority": freeze_authority.to_string(),
972 })
973 }
974 );
975
976 let account_pubkey = Pubkey::new_unique();
978 let owner = Pubkey::new_unique();
979 let initialize_account_ix =
980 initialize_account(program_id, &account_pubkey, &mint_pubkey, &owner).unwrap();
981 let message = Message::new(&[initialize_account_ix], None);
982 let compiled_instruction = &message.instructions[0];
983 assert_eq!(
984 parse_token(
985 compiled_instruction,
986 &AccountKeys::new(&message.account_keys, None)
987 )
988 .unwrap(),
989 ParsedInstructionEnum {
990 instruction_type: "initializeAccount".to_string(),
991 info: json!({
992 "account": account_pubkey.to_string(),
993 "mint": mint_pubkey.to_string(),
994 "owner": owner.to_string(),
995 "rentSysvar": rent_sysvar.to_string(),
996 })
997 }
998 );
999
1000 let initialize_account_ix =
1002 initialize_account2(program_id, &account_pubkey, &mint_pubkey, &owner).unwrap();
1003 let message = Message::new(&[initialize_account_ix], None);
1004 let compiled_instruction = &message.instructions[0];
1005 assert_eq!(
1006 parse_token(
1007 compiled_instruction,
1008 &AccountKeys::new(&message.account_keys, None)
1009 )
1010 .unwrap(),
1011 ParsedInstructionEnum {
1012 instruction_type: "initializeAccount2".to_string(),
1013 info: json!({
1014 "account": account_pubkey.to_string(),
1015 "mint": mint_pubkey.to_string(),
1016 "owner": owner.to_string(),
1017 "rentSysvar": rent_sysvar.to_string(),
1018 })
1019 }
1020 );
1021
1022 let initialize_account_ix =
1024 initialize_account3(program_id, &account_pubkey, &mint_pubkey, &owner).unwrap();
1025 let message = Message::new(&[initialize_account_ix], None);
1026 let compiled_instruction = &message.instructions[0];
1027 assert_eq!(
1028 parse_token(
1029 compiled_instruction,
1030 &AccountKeys::new(&message.account_keys, None)
1031 )
1032 .unwrap(),
1033 ParsedInstructionEnum {
1034 instruction_type: "initializeAccount3".to_string(),
1035 info: json!({
1036 "account": account_pubkey.to_string(),
1037 "mint": mint_pubkey.to_string(),
1038 "owner": owner.to_string(),
1039 })
1040 }
1041 );
1042
1043 let multisig_pubkey = Pubkey::new_unique();
1045 let multisig_signer0 = Pubkey::new_unique();
1046 let multisig_signer1 = Pubkey::new_unique();
1047 let multisig_signer2 = Pubkey::new_unique();
1048 let initialize_multisig_ix = initialize_multisig(
1049 program_id,
1050 &multisig_pubkey,
1051 &[&multisig_signer0, &multisig_signer1, &multisig_signer2],
1052 2,
1053 )
1054 .unwrap();
1055 let message = Message::new(&[initialize_multisig_ix], None);
1056 let compiled_instruction = &message.instructions[0];
1057 assert_eq!(
1058 parse_token(
1059 compiled_instruction,
1060 &AccountKeys::new(&message.account_keys, None)
1061 )
1062 .unwrap(),
1063 ParsedInstructionEnum {
1064 instruction_type: "initializeMultisig".to_string(),
1065 info: json!({
1066 "multisig": multisig_pubkey.to_string(),
1067 "m": 2,
1068 "rentSysvar": rent_sysvar.to_string(),
1069 "signers": vec![
1070 multisig_signer0.to_string(),
1071 multisig_signer1.to_string(),
1072 multisig_signer2.to_string(),
1073 ],
1074 })
1075 }
1076 );
1077
1078 let initialize_multisig_ix = initialize_multisig2(
1080 program_id,
1081 &multisig_pubkey,
1082 &[&multisig_signer0, &multisig_signer1, &multisig_signer2],
1083 2,
1084 )
1085 .unwrap();
1086 let message = Message::new(&[initialize_multisig_ix], None);
1087 let compiled_instruction = &message.instructions[0];
1088 assert_eq!(
1089 parse_token(
1090 compiled_instruction,
1091 &AccountKeys::new(&message.account_keys, None)
1092 )
1093 .unwrap(),
1094 ParsedInstructionEnum {
1095 instruction_type: "initializeMultisig2".to_string(),
1096 info: json!({
1097 "multisig": multisig_pubkey.to_string(),
1098 "m": 2,
1099 "signers": vec![
1100 multisig_signer0.to_string(),
1101 multisig_signer1.to_string(),
1102 multisig_signer2.to_string(),
1103 ],
1104 })
1105 }
1106 );
1107
1108 let recipient = Pubkey::new_unique();
1110 #[allow(deprecated)]
1111 let transfer_ix =
1112 transfer(program_id, &account_pubkey, &recipient, &owner, &[], 42).unwrap();
1113 let message = Message::new(&[transfer_ix], None);
1114 let compiled_instruction = &message.instructions[0];
1115 assert_eq!(
1116 parse_token(
1117 compiled_instruction,
1118 &AccountKeys::new(&message.account_keys, None)
1119 )
1120 .unwrap(),
1121 ParsedInstructionEnum {
1122 instruction_type: "transfer".to_string(),
1123 info: json!({
1124 "source": account_pubkey.to_string(),
1125 "destination": recipient.to_string(),
1126 "authority": owner.to_string(),
1127 "amount": "42",
1128 })
1129 }
1130 );
1131
1132 #[allow(deprecated)]
1133 let transfer_ix = transfer(
1134 program_id,
1135 &account_pubkey,
1136 &recipient,
1137 &multisig_pubkey,
1138 &[&multisig_signer0, &multisig_signer1],
1139 42,
1140 )
1141 .unwrap();
1142 let message = Message::new(&[transfer_ix], None);
1143 let compiled_instruction = &message.instructions[0];
1144 assert_eq!(
1145 parse_token(
1146 compiled_instruction,
1147 &AccountKeys::new(&message.account_keys, None)
1148 )
1149 .unwrap(),
1150 ParsedInstructionEnum {
1151 instruction_type: "transfer".to_string(),
1152 info: json!({
1153 "source": account_pubkey.to_string(),
1154 "destination": recipient.to_string(),
1155 "multisigAuthority": multisig_pubkey.to_string(),
1156 "signers": vec![
1157 multisig_signer0.to_string(),
1158 multisig_signer1.to_string(),
1159 ],
1160 "amount": "42",
1161 })
1162 }
1163 );
1164
1165 let approve_ix = approve(program_id, &account_pubkey, &recipient, &owner, &[], 42).unwrap();
1167 let message = Message::new(&[approve_ix], None);
1168 let compiled_instruction = &message.instructions[0];
1169 assert_eq!(
1170 parse_token(
1171 compiled_instruction,
1172 &AccountKeys::new(&message.account_keys, None)
1173 )
1174 .unwrap(),
1175 ParsedInstructionEnum {
1176 instruction_type: "approve".to_string(),
1177 info: json!({
1178 "source": account_pubkey.to_string(),
1179 "delegate": recipient.to_string(),
1180 "owner": owner.to_string(),
1181 "amount": "42",
1182 })
1183 }
1184 );
1185
1186 let approve_ix = approve(
1187 program_id,
1188 &account_pubkey,
1189 &recipient,
1190 &multisig_pubkey,
1191 &[&multisig_signer0, &multisig_signer1],
1192 42,
1193 )
1194 .unwrap();
1195 let message = Message::new(&[approve_ix], None);
1196 let compiled_instruction = &message.instructions[0];
1197 assert_eq!(
1198 parse_token(
1199 compiled_instruction,
1200 &AccountKeys::new(&message.account_keys, None)
1201 )
1202 .unwrap(),
1203 ParsedInstructionEnum {
1204 instruction_type: "approve".to_string(),
1205 info: json!({
1206 "source": account_pubkey.to_string(),
1207 "delegate": recipient.to_string(),
1208 "multisigOwner": multisig_pubkey.to_string(),
1209 "signers": vec![
1210 multisig_signer0.to_string(),
1211 multisig_signer1.to_string(),
1212 ],
1213 "amount": "42",
1214 })
1215 }
1216 );
1217
1218 let revoke_ix = revoke(program_id, &account_pubkey, &owner, &[]).unwrap();
1220 let message = Message::new(&[revoke_ix], None);
1221 let compiled_instruction = &message.instructions[0];
1222 assert_eq!(
1223 parse_token(
1224 compiled_instruction,
1225 &AccountKeys::new(&message.account_keys, None)
1226 )
1227 .unwrap(),
1228 ParsedInstructionEnum {
1229 instruction_type: "revoke".to_string(),
1230 info: json!({
1231 "source": account_pubkey.to_string(),
1232 "owner": owner.to_string(),
1233 })
1234 }
1235 );
1236
1237 let new_freeze_authority = Pubkey::new_unique();
1239 let set_authority_ix = set_authority(
1240 program_id,
1241 &mint_pubkey,
1242 Some(&new_freeze_authority),
1243 AuthorityType::FreezeAccount,
1244 &freeze_authority,
1245 &[],
1246 )
1247 .unwrap();
1248 let message = Message::new(&[set_authority_ix], None);
1249 let compiled_instruction = &message.instructions[0];
1250 assert_eq!(
1251 parse_token(
1252 compiled_instruction,
1253 &AccountKeys::new(&message.account_keys, None)
1254 )
1255 .unwrap(),
1256 ParsedInstructionEnum {
1257 instruction_type: "setAuthority".to_string(),
1258 info: json!({
1259 "mint": mint_pubkey.to_string(),
1260 "newAuthority": new_freeze_authority.to_string(),
1261 "authority": freeze_authority.to_string(),
1262 "authorityType": "freezeAccount".to_string(),
1263 })
1264 }
1265 );
1266
1267 let set_authority_ix = set_authority(
1268 program_id,
1269 &account_pubkey,
1270 None,
1271 AuthorityType::CloseAccount,
1272 &owner,
1273 &[],
1274 )
1275 .unwrap();
1276 let message = Message::new(&[set_authority_ix], None);
1277 let compiled_instruction = &message.instructions[0];
1278 let new_authority: Option<String> = None;
1279 assert_eq!(
1280 parse_token(
1281 compiled_instruction,
1282 &AccountKeys::new(&message.account_keys, None)
1283 )
1284 .unwrap(),
1285 ParsedInstructionEnum {
1286 instruction_type: "setAuthority".to_string(),
1287 info: json!({
1288 "account": account_pubkey.to_string(),
1289 "newAuthority": new_authority,
1290 "authority": owner.to_string(),
1291 "authorityType": "closeAccount".to_string(),
1292 })
1293 }
1294 );
1295
1296 let mint_to_ix = mint_to(
1298 program_id,
1299 &mint_pubkey,
1300 &account_pubkey,
1301 &mint_authority,
1302 &[],
1303 42,
1304 )
1305 .unwrap();
1306 let message = Message::new(&[mint_to_ix], None);
1307 let compiled_instruction = &message.instructions[0];
1308 assert_eq!(
1309 parse_token(
1310 compiled_instruction,
1311 &AccountKeys::new(&message.account_keys, None)
1312 )
1313 .unwrap(),
1314 ParsedInstructionEnum {
1315 instruction_type: "mintTo".to_string(),
1316 info: json!({
1317 "mint": mint_pubkey.to_string(),
1318 "account": account_pubkey.to_string(),
1319 "mintAuthority": mint_authority.to_string(),
1320 "amount": "42",
1321 })
1322 }
1323 );
1324
1325 let burn_ix = burn(program_id, &account_pubkey, &mint_pubkey, &owner, &[], 42).unwrap();
1327 let message = Message::new(&[burn_ix], None);
1328 let compiled_instruction = &message.instructions[0];
1329 assert_eq!(
1330 parse_token(
1331 compiled_instruction,
1332 &AccountKeys::new(&message.account_keys, None)
1333 )
1334 .unwrap(),
1335 ParsedInstructionEnum {
1336 instruction_type: "burn".to_string(),
1337 info: json!({
1338 "account": account_pubkey.to_string(),
1339 "mint": mint_pubkey.to_string(),
1340 "authority": owner.to_string(),
1341 "amount": "42",
1342 })
1343 }
1344 );
1345
1346 let close_account_ix =
1348 close_account(program_id, &account_pubkey, &recipient, &owner, &[]).unwrap();
1349 let message = Message::new(&[close_account_ix], None);
1350 let compiled_instruction = &message.instructions[0];
1351 assert_eq!(
1352 parse_token(
1353 compiled_instruction,
1354 &AccountKeys::new(&message.account_keys, None)
1355 )
1356 .unwrap(),
1357 ParsedInstructionEnum {
1358 instruction_type: "closeAccount".to_string(),
1359 info: json!({
1360 "account": account_pubkey.to_string(),
1361 "destination": recipient.to_string(),
1362 "owner": owner.to_string(),
1363 })
1364 }
1365 );
1366
1367 let freeze_account_ix = freeze_account(
1369 program_id,
1370 &account_pubkey,
1371 &mint_pubkey,
1372 &freeze_authority,
1373 &[],
1374 )
1375 .unwrap();
1376 let message = Message::new(&[freeze_account_ix], None);
1377 let compiled_instruction = &message.instructions[0];
1378 assert_eq!(
1379 parse_token(
1380 compiled_instruction,
1381 &AccountKeys::new(&message.account_keys, None)
1382 )
1383 .unwrap(),
1384 ParsedInstructionEnum {
1385 instruction_type: "freezeAccount".to_string(),
1386 info: json!({
1387 "account": account_pubkey.to_string(),
1388 "mint": mint_pubkey.to_string(),
1389 "freezeAuthority": freeze_authority.to_string(),
1390 })
1391 }
1392 );
1393
1394 let thaw_account_ix = thaw_account(
1396 program_id,
1397 &account_pubkey,
1398 &mint_pubkey,
1399 &freeze_authority,
1400 &[],
1401 )
1402 .unwrap();
1403 let message = Message::new(&[thaw_account_ix], None);
1404 let compiled_instruction = &message.instructions[0];
1405 assert_eq!(
1406 parse_token(
1407 compiled_instruction,
1408 &AccountKeys::new(&message.account_keys, None)
1409 )
1410 .unwrap(),
1411 ParsedInstructionEnum {
1412 instruction_type: "thawAccount".to_string(),
1413 info: json!({
1414 "account": account_pubkey.to_string(),
1415 "mint": mint_pubkey.to_string(),
1416 "freezeAuthority": freeze_authority.to_string(),
1417 })
1418 }
1419 );
1420
1421 let transfer_ix = transfer_checked(
1423 program_id,
1424 &account_pubkey,
1425 &mint_pubkey,
1426 &recipient,
1427 &owner,
1428 &[],
1429 42,
1430 2,
1431 )
1432 .unwrap();
1433 let message = Message::new(&[transfer_ix], None);
1434 let compiled_instruction = &message.instructions[0];
1435 assert_eq!(
1436 parse_token(
1437 compiled_instruction,
1438 &AccountKeys::new(&message.account_keys, None)
1439 )
1440 .unwrap(),
1441 ParsedInstructionEnum {
1442 instruction_type: "transferChecked".to_string(),
1443 info: json!({
1444 "source": account_pubkey.to_string(),
1445 "destination": recipient.to_string(),
1446 "mint": mint_pubkey.to_string(),
1447 "authority": owner.to_string(),
1448 "tokenAmount": {
1449 "uiAmount": 0.42,
1450 "decimals": 2,
1451 "amount": "42",
1452 "uiAmountString": "0.42",
1453 }
1454 })
1455 }
1456 );
1457
1458 let transfer_ix = transfer_checked(
1459 program_id,
1460 &account_pubkey,
1461 &mint_pubkey,
1462 &recipient,
1463 &multisig_pubkey,
1464 &[&multisig_signer0, &multisig_signer1],
1465 42,
1466 2,
1467 )
1468 .unwrap();
1469 let message = Message::new(&[transfer_ix], None);
1470 let compiled_instruction = &message.instructions[0];
1471 assert_eq!(
1472 parse_token(
1473 compiled_instruction,
1474 &AccountKeys::new(&message.account_keys, None)
1475 )
1476 .unwrap(),
1477 ParsedInstructionEnum {
1478 instruction_type: "transferChecked".to_string(),
1479 info: json!({
1480 "source": account_pubkey.to_string(),
1481 "destination": recipient.to_string(),
1482 "mint": mint_pubkey.to_string(),
1483 "multisigAuthority": multisig_pubkey.to_string(),
1484 "signers": vec![
1485 multisig_signer0.to_string(),
1486 multisig_signer1.to_string(),
1487 ],
1488 "tokenAmount": {
1489 "uiAmount": 0.42,
1490 "decimals": 2,
1491 "amount": "42",
1492 "uiAmountString": "0.42",
1493 }
1494 })
1495 }
1496 );
1497
1498 let approve_ix = approve_checked(
1500 program_id,
1501 &account_pubkey,
1502 &mint_pubkey,
1503 &recipient,
1504 &owner,
1505 &[],
1506 42,
1507 2,
1508 )
1509 .unwrap();
1510 let message = Message::new(&[approve_ix], None);
1511 let compiled_instruction = &message.instructions[0];
1512 assert_eq!(
1513 parse_token(
1514 compiled_instruction,
1515 &AccountKeys::new(&message.account_keys, None)
1516 )
1517 .unwrap(),
1518 ParsedInstructionEnum {
1519 instruction_type: "approveChecked".to_string(),
1520 info: json!({
1521 "source": account_pubkey.to_string(),
1522 "mint": mint_pubkey.to_string(),
1523 "delegate": recipient.to_string(),
1524 "owner": owner.to_string(),
1525 "tokenAmount": {
1526 "uiAmount": 0.42,
1527 "decimals": 2,
1528 "amount": "42",
1529 "uiAmountString": "0.42",
1530 }
1531 })
1532 }
1533 );
1534
1535 let approve_ix = approve_checked(
1536 program_id,
1537 &account_pubkey,
1538 &mint_pubkey,
1539 &recipient,
1540 &multisig_pubkey,
1541 &[&multisig_signer0, &multisig_signer1],
1542 42,
1543 2,
1544 )
1545 .unwrap();
1546 let message = Message::new(&[approve_ix], None);
1547 let compiled_instruction = &message.instructions[0];
1548 assert_eq!(
1549 parse_token(
1550 compiled_instruction,
1551 &AccountKeys::new(&message.account_keys, None)
1552 )
1553 .unwrap(),
1554 ParsedInstructionEnum {
1555 instruction_type: "approveChecked".to_string(),
1556 info: json!({
1557 "source": account_pubkey.to_string(),
1558 "mint": mint_pubkey.to_string(),
1559 "delegate": recipient.to_string(),
1560 "multisigOwner": multisig_pubkey.to_string(),
1561 "signers": vec![
1562 multisig_signer0.to_string(),
1563 multisig_signer1.to_string(),
1564 ],
1565 "tokenAmount": {
1566 "uiAmount": 0.42,
1567 "decimals": 2,
1568 "amount": "42",
1569 "uiAmountString": "0.42",
1570 }
1571 })
1572 }
1573 );
1574
1575 let mint_to_ix = mint_to_checked(
1577 program_id,
1578 &mint_pubkey,
1579 &account_pubkey,
1580 &mint_authority,
1581 &[],
1582 42,
1583 2,
1584 )
1585 .unwrap();
1586 let message = Message::new(&[mint_to_ix], None);
1587 let compiled_instruction = &message.instructions[0];
1588 assert_eq!(
1589 parse_token(
1590 compiled_instruction,
1591 &AccountKeys::new(&message.account_keys, None)
1592 )
1593 .unwrap(),
1594 ParsedInstructionEnum {
1595 instruction_type: "mintToChecked".to_string(),
1596 info: json!({
1597 "mint": mint_pubkey.to_string(),
1598 "account": account_pubkey.to_string(),
1599 "mintAuthority": mint_authority.to_string(),
1600 "tokenAmount": {
1601 "uiAmount": 0.42,
1602 "decimals": 2,
1603 "amount": "42",
1604 "uiAmountString": "0.42",
1605 }
1606 })
1607 }
1608 );
1609
1610 let burn_ix = burn_checked(
1612 program_id,
1613 &account_pubkey,
1614 &mint_pubkey,
1615 &owner,
1616 &[],
1617 42,
1618 2,
1619 )
1620 .unwrap();
1621 let message = Message::new(&[burn_ix], None);
1622 let compiled_instruction = &message.instructions[0];
1623 assert_eq!(
1624 parse_token(
1625 compiled_instruction,
1626 &AccountKeys::new(&message.account_keys, None)
1627 )
1628 .unwrap(),
1629 ParsedInstructionEnum {
1630 instruction_type: "burnChecked".to_string(),
1631 info: json!({
1632 "account": account_pubkey.to_string(),
1633 "mint": mint_pubkey.to_string(),
1634 "authority": owner.to_string(),
1635 "tokenAmount": {
1636 "uiAmount": 0.42,
1637 "decimals": 2,
1638 "amount": "42",
1639 "uiAmountString": "0.42",
1640 }
1641 })
1642 }
1643 );
1644
1645 let sync_native_ix = sync_native(program_id, &account_pubkey).unwrap();
1647 let message = Message::new(&[sync_native_ix], None);
1648 let compiled_instruction = &message.instructions[0];
1649 assert_eq!(
1650 parse_token(
1651 compiled_instruction,
1652 &AccountKeys::new(&message.account_keys, None)
1653 )
1654 .unwrap(),
1655 ParsedInstructionEnum {
1656 instruction_type: "syncNative".to_string(),
1657 info: json!({
1658 "account": account_pubkey.to_string(),
1659 })
1660 }
1661 );
1662
1663 let init_immutable_owner_ix =
1665 initialize_immutable_owner(program_id, &account_pubkey).unwrap();
1666 let message = Message::new(&[init_immutable_owner_ix], None);
1667 let compiled_instruction = &message.instructions[0];
1668 assert_eq!(
1669 parse_token(
1670 compiled_instruction,
1671 &AccountKeys::new(&message.account_keys, None)
1672 )
1673 .unwrap(),
1674 ParsedInstructionEnum {
1675 instruction_type: "initializeImmutableOwner".to_string(),
1676 info: json!({
1677 "account": account_pubkey.to_string(),
1678 })
1679 }
1680 );
1681
1682 let get_account_data_size_ix = get_account_data_size(
1684 program_id,
1685 &mint_pubkey,
1686 &[], )
1688 .unwrap();
1689 let message = Message::new(&[get_account_data_size_ix], None);
1690 let compiled_instruction = &message.instructions[0];
1691 assert_eq!(
1692 parse_token(
1693 compiled_instruction,
1694 &AccountKeys::new(&message.account_keys, None)
1695 )
1696 .unwrap(),
1697 ParsedInstructionEnum {
1698 instruction_type: "getAccountDataSize".to_string(),
1699 info: json!({
1700 "mint": mint_pubkey.to_string(),
1701 })
1702 }
1703 );
1704
1705 let get_account_data_size_ix = get_account_data_size(
1706 program_id,
1707 &mint_pubkey,
1708 &[ExtensionType::ImmutableOwner, ExtensionType::MemoTransfer],
1709 )
1710 .unwrap();
1711 let message = Message::new(&[get_account_data_size_ix], None);
1712 let compiled_instruction = &message.instructions[0];
1713 assert_eq!(
1714 parse_token(
1715 compiled_instruction,
1716 &AccountKeys::new(&message.account_keys, None)
1717 )
1718 .unwrap(),
1719 ParsedInstructionEnum {
1720 instruction_type: "getAccountDataSize".to_string(),
1721 info: json!({
1722 "mint": mint_pubkey.to_string(),
1723 "extensionTypes": [
1724 "immutableOwner",
1725 "memoTransfer"
1726 ]
1727 })
1728 }
1729 );
1730
1731 let amount_to_ui_amount_ix = amount_to_ui_amount(program_id, &mint_pubkey, 4242).unwrap();
1733 let message = Message::new(&[amount_to_ui_amount_ix], None);
1734 let compiled_instruction = &message.instructions[0];
1735 assert_eq!(
1736 parse_token(
1737 compiled_instruction,
1738 &AccountKeys::new(&message.account_keys, None)
1739 )
1740 .unwrap(),
1741 ParsedInstructionEnum {
1742 instruction_type: "amountToUiAmount".to_string(),
1743 info: json!({
1744 "mint": mint_pubkey.to_string(),
1745 "amount": "4242",
1746 })
1747 }
1748 );
1749
1750 let ui_amount_to_amount_ix =
1752 ui_amount_to_amount(program_id, &mint_pubkey, "42.42").unwrap();
1753 let message = Message::new(&[ui_amount_to_amount_ix], None);
1754 let compiled_instruction = &message.instructions[0];
1755 assert_eq!(
1756 parse_token(
1757 compiled_instruction,
1758 &AccountKeys::new(&message.account_keys, None)
1759 )
1760 .unwrap(),
1761 ParsedInstructionEnum {
1762 instruction_type: "uiAmountToAmount".to_string(),
1763 info: json!({
1764 "mint": mint_pubkey.to_string(),
1765 "uiAmount": "42.42",
1766 })
1767 }
1768 );
1769 }
1770
1771 #[test]
1772 fn test_parse_token_v3() {
1773 test_parse_token(&spl_token::id());
1774 }
1775
1776 #[test]
1777 fn test_parse_token_2022() {
1778 test_parse_token(&spl_token_2022::id());
1779 }
1780
1781 #[test]
1782 fn test_create_native_mint() {
1783 let payer = Pubkey::new_unique();
1784 let create_native_mint_ix = create_native_mint(&spl_token_2022::id(), &payer).unwrap();
1785 let message = Message::new(&[create_native_mint_ix], None);
1786 let compiled_instruction = &message.instructions[0];
1787 assert_eq!(
1788 parse_token(
1789 compiled_instruction,
1790 &AccountKeys::new(&message.account_keys, None)
1791 )
1792 .unwrap(),
1793 ParsedInstructionEnum {
1794 instruction_type: "createNativeMint".to_string(),
1795 info: json!({
1796 "payer": payer.to_string(),
1797 "nativeMint": spl_token_2022::native_mint::id().to_string(),
1798 "systemProgram": solana_sdk_ids::system_program::id().to_string(),
1799 })
1800 }
1801 );
1802 }
1803
1804 fn test_token_ix_not_enough_keys(program_id: &Pubkey) {
1805 let keys: Vec<Pubkey> = repeat_with(solana_pubkey::new_rand).take(10).collect();
1806
1807 let initialize_mint_ix =
1809 initialize_mint(program_id, &keys[0], &keys[1], Some(&keys[2]), 2).unwrap();
1810 let mut message = Message::new(&[initialize_mint_ix], None);
1811 let compiled_instruction = &mut message.instructions[0];
1812 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1813 compiled_instruction.accounts =
1814 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1815 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1816
1817 let initialize_mint_ix = initialize_mint(program_id, &keys[0], &keys[1], None, 2).unwrap();
1818 let mut message = Message::new(&[initialize_mint_ix], None);
1819 let compiled_instruction = &mut message.instructions[0];
1820 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1821 compiled_instruction.accounts =
1822 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1823 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1824
1825 let initialize_mint_ix =
1827 initialize_mint2(program_id, &keys[0], &keys[1], Some(&keys[2]), 2).unwrap();
1828 let mut message = Message::new(&[initialize_mint_ix], None);
1829 let compiled_instruction = &mut message.instructions[0];
1830 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..0], None)).is_err());
1831 compiled_instruction.accounts =
1832 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1833 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1834
1835 let initialize_account_ix =
1837 initialize_account(program_id, &keys[0], &keys[1], &keys[2]).unwrap();
1838 let mut message = Message::new(&[initialize_account_ix], None);
1839 let compiled_instruction = &mut message.instructions[0];
1840 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
1841 compiled_instruction.accounts =
1842 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1843 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1844
1845 let initialize_account_ix =
1847 initialize_account2(program_id, &keys[0], &keys[1], &keys[3]).unwrap();
1848 let mut message = Message::new(&[initialize_account_ix], None);
1849 let compiled_instruction = &mut message.instructions[0];
1850 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1851 compiled_instruction.accounts =
1852 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1853 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1854
1855 let initialize_account_ix =
1857 initialize_account3(program_id, &keys[0], &keys[1], &keys[2]).unwrap();
1858 let mut message = Message::new(&[initialize_account_ix], None);
1859 let compiled_instruction = &mut message.instructions[0];
1860 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1861 compiled_instruction.accounts =
1862 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1863 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1864
1865 let initialize_multisig_ix =
1867 initialize_multisig(program_id, &keys[0], &[&keys[1], &keys[2], &keys[3]], 2).unwrap();
1868 let mut message = Message::new(&[initialize_multisig_ix], None);
1869 let compiled_instruction = &mut message.instructions[0];
1870 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
1871 compiled_instruction.accounts =
1872 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1873 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1874
1875 let initialize_multisig_ix =
1877 initialize_multisig2(program_id, &keys[0], &[&keys[1], &keys[2], &keys[3]], 2).unwrap();
1878 let mut message = Message::new(&[initialize_multisig_ix], None);
1879 let compiled_instruction = &mut message.instructions[0];
1880 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
1881 compiled_instruction.accounts =
1882 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1883 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1884
1885 #[allow(deprecated)]
1887 let transfer_ix = transfer(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1888 let mut message = Message::new(&[transfer_ix], None);
1889 let compiled_instruction = &mut message.instructions[0];
1890 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1891 compiled_instruction.accounts =
1892 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1893 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1894
1895 #[allow(deprecated)]
1896 let transfer_ix = transfer(
1897 program_id,
1898 &keys[2],
1899 &keys[3],
1900 &keys[4],
1901 &[&keys[0], &keys[1]],
1902 42,
1903 )
1904 .unwrap();
1905 let mut message = Message::new(&[transfer_ix], None);
1906 let compiled_instruction = &mut message.instructions[0];
1907 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
1908 compiled_instruction.accounts =
1909 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1910 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1911
1912 let approve_ix = approve(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1914 let mut message = Message::new(&[approve_ix], None);
1915 let compiled_instruction = &mut message.instructions[0];
1916 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1917 compiled_instruction.accounts =
1918 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1919 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1920
1921 let approve_ix = approve(
1922 program_id,
1923 &keys[2],
1924 &keys[3],
1925 &keys[4],
1926 &[&keys[0], &keys[1]],
1927 42,
1928 )
1929 .unwrap();
1930 let mut message = Message::new(&[approve_ix], None);
1931 let compiled_instruction = &mut message.instructions[0];
1932 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
1933 compiled_instruction.accounts =
1934 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1935 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1936
1937 let revoke_ix = revoke(program_id, &keys[1], &keys[0], &[]).unwrap();
1939 let mut message = Message::new(&[revoke_ix], None);
1940 let compiled_instruction = &mut message.instructions[0];
1941 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1942 compiled_instruction.accounts =
1943 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1944 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1945
1946 let set_authority_ix = set_authority(
1948 program_id,
1949 &keys[1],
1950 Some(&keys[2]),
1951 AuthorityType::FreezeAccount,
1952 &keys[0],
1953 &[],
1954 )
1955 .unwrap();
1956 let mut message = Message::new(&[set_authority_ix], None);
1957 let compiled_instruction = &mut message.instructions[0];
1958 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1959 compiled_instruction.accounts =
1960 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1961 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1962
1963 let mint_to_ix = mint_to(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1965 let mut message = Message::new(&[mint_to_ix], None);
1966 let compiled_instruction = &mut message.instructions[0];
1967 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1968 compiled_instruction.accounts =
1969 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1970 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1971
1972 let burn_ix = burn(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1974 let mut message = Message::new(&[burn_ix], None);
1975 let compiled_instruction = &mut message.instructions[0];
1976 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1977 compiled_instruction.accounts =
1978 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1979 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1980
1981 let close_account_ix =
1983 close_account(program_id, &keys[1], &keys[2], &keys[0], &[]).unwrap();
1984 let mut message = Message::new(&[close_account_ix], None);
1985 let compiled_instruction = &mut message.instructions[0];
1986 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1987 compiled_instruction.accounts =
1988 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1989 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1990
1991 let freeze_account_ix =
1993 freeze_account(program_id, &keys[1], &keys[2], &keys[0], &[]).unwrap();
1994 let mut message = Message::new(&[freeze_account_ix], None);
1995 let compiled_instruction = &mut message.instructions[0];
1996 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1997 compiled_instruction.accounts =
1998 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1999 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2000
2001 let thaw_account_ix = thaw_account(program_id, &keys[1], &keys[2], &keys[0], &[]).unwrap();
2003 let mut message = Message::new(&[thaw_account_ix], None);
2004 let compiled_instruction = &mut message.instructions[0];
2005 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2006 compiled_instruction.accounts =
2007 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2008 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2009
2010 let transfer_ix = transfer_checked(
2012 program_id,
2013 &keys[1],
2014 &keys[2],
2015 &keys[3],
2016 &keys[0],
2017 &[],
2018 42,
2019 2,
2020 )
2021 .unwrap();
2022 let mut message = Message::new(&[transfer_ix], None);
2023 let compiled_instruction = &mut message.instructions[0];
2024 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
2025 compiled_instruction.accounts =
2026 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2027 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2028
2029 let transfer_ix = transfer_checked(
2030 program_id,
2031 &keys[2],
2032 &keys[3],
2033 &keys[4],
2034 &keys[5],
2035 &[&keys[0], &keys[1]],
2036 42,
2037 2,
2038 )
2039 .unwrap();
2040 let mut message = Message::new(&[transfer_ix], None);
2041 let compiled_instruction = &mut message.instructions[0];
2042 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..5], None)).is_err());
2043 compiled_instruction.accounts =
2044 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
2045 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2046
2047 let approve_ix = approve_checked(
2049 program_id,
2050 &keys[1],
2051 &keys[2],
2052 &keys[3],
2053 &keys[0],
2054 &[],
2055 42,
2056 2,
2057 )
2058 .unwrap();
2059 let mut message = Message::new(&[approve_ix], None);
2060 let compiled_instruction = &mut message.instructions[0];
2061 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
2062 compiled_instruction.accounts =
2063 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2064 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2065
2066 let approve_ix = approve_checked(
2067 program_id,
2068 &keys[2],
2069 &keys[3],
2070 &keys[4],
2071 &keys[5],
2072 &[&keys[0], &keys[1]],
2073 42,
2074 2,
2075 )
2076 .unwrap();
2077 let mut message = Message::new(&[approve_ix], None);
2078 let compiled_instruction = &mut message.instructions[0];
2079 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..5], None)).is_err());
2080 compiled_instruction.accounts =
2081 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
2082 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2083
2084 let mint_to_ix =
2086 mint_to_checked(program_id, &keys[1], &keys[2], &keys[0], &[], 42, 2).unwrap();
2087 let mut message = Message::new(&[mint_to_ix], None);
2088 let compiled_instruction = &mut message.instructions[0];
2089 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2090 compiled_instruction.accounts =
2091 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2092 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2093
2094 let burn_ix = burn_checked(program_id, &keys[1], &keys[2], &keys[0], &[], 42, 2).unwrap();
2096 let mut message = Message::new(&[burn_ix], None);
2097 let compiled_instruction = &mut message.instructions[0];
2098 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2099 compiled_instruction.accounts =
2100 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2101 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2102
2103 let sync_native_ix = sync_native(program_id, &keys[0]).unwrap();
2105 let mut message = Message::new(&[sync_native_ix], None);
2106 let compiled_instruction = &mut message.instructions[0];
2107 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2108 compiled_instruction.accounts =
2109 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2110 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2111
2112 let init_immutable_owner_ix = initialize_immutable_owner(program_id, &keys[0]).unwrap();
2114 let mut message = Message::new(&[init_immutable_owner_ix], None);
2115 let compiled_instruction = &mut message.instructions[0];
2116 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2117 compiled_instruction.accounts =
2118 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2119 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2120
2121 let get_account_data_size_ix = get_account_data_size(program_id, &keys[0], &[]).unwrap();
2123 let mut message = Message::new(&[get_account_data_size_ix], None);
2124 let compiled_instruction = &mut message.instructions[0];
2125 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2126 compiled_instruction.accounts =
2127 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2128 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2129
2130 let amount_to_ui_amount_ix = amount_to_ui_amount(program_id, &keys[0], 4242).unwrap();
2132 let mut message = Message::new(&[amount_to_ui_amount_ix], None);
2133 let compiled_instruction = &mut message.instructions[0];
2134 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2135 compiled_instruction.accounts =
2136 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2137 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2138
2139 let ui_amount_to_amount_ix = ui_amount_to_amount(program_id, &keys[0], "42.42").unwrap();
2141 let mut message = Message::new(&[ui_amount_to_amount_ix], None);
2142 let compiled_instruction = &mut message.instructions[0];
2143 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2144 compiled_instruction.accounts =
2145 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2146 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2147 }
2148
2149 #[test]
2150 fn test_not_enough_keys_token_v3() {
2151 test_token_ix_not_enough_keys(&spl_token::id());
2152 }
2153
2154 #[test]
2155 fn test_not_enough_keys_token_2022() {
2156 test_token_ix_not_enough_keys(&spl_token_2022::id());
2157 }
2158}