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