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