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_interface::extension::ExtensionType;
30use spl_token_2022_interface::instruction::AuthorityType;
31use spl_token_2022_interface::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_interface::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 &[], )
1713 .unwrap();
1714 let message = Message::new(&[get_account_data_size_ix], None);
1715 let compiled_instruction = &message.instructions[0];
1716 assert_eq!(
1717 parse_token(
1718 compiled_instruction,
1719 &AccountKeys::new(&message.account_keys, None)
1720 )
1721 .unwrap(),
1722 ParsedInstructionEnum {
1723 instruction_type: "getAccountDataSize".to_string(),
1724 info: json!({
1725 "mint": mint_pubkey.to_string(),
1726 })
1727 }
1728 );
1729
1730 let get_account_data_size_ix = get_account_data_size(
1731 program_id,
1732 &mint_pubkey,
1733 &[ExtensionType::ImmutableOwner, ExtensionType::MemoTransfer],
1734 )
1735 .unwrap();
1736 let message = Message::new(&[get_account_data_size_ix], None);
1737 let compiled_instruction = &message.instructions[0];
1738 assert_eq!(
1739 parse_token(
1740 compiled_instruction,
1741 &AccountKeys::new(&message.account_keys, None)
1742 )
1743 .unwrap(),
1744 ParsedInstructionEnum {
1745 instruction_type: "getAccountDataSize".to_string(),
1746 info: json!({
1747 "mint": mint_pubkey.to_string(),
1748 "extensionTypes": [
1749 "immutableOwner",
1750 "memoTransfer"
1751 ]
1752 })
1753 }
1754 );
1755
1756 let amount_to_ui_amount_ix = amount_to_ui_amount(program_id, &mint_pubkey, 4242).unwrap();
1758 let message = Message::new(&[amount_to_ui_amount_ix], None);
1759 let compiled_instruction = &message.instructions[0];
1760 assert_eq!(
1761 parse_token(
1762 compiled_instruction,
1763 &AccountKeys::new(&message.account_keys, None)
1764 )
1765 .unwrap(),
1766 ParsedInstructionEnum {
1767 instruction_type: "amountToUiAmount".to_string(),
1768 info: json!({
1769 "mint": mint_pubkey.to_string(),
1770 "amount": "4242",
1771 })
1772 }
1773 );
1774
1775 let ui_amount_to_amount_ix =
1777 ui_amount_to_amount(program_id, &mint_pubkey, "42.42").unwrap();
1778 let message = Message::new(&[ui_amount_to_amount_ix], None);
1779 let compiled_instruction = &message.instructions[0];
1780 assert_eq!(
1781 parse_token(
1782 compiled_instruction,
1783 &AccountKeys::new(&message.account_keys, None)
1784 )
1785 .unwrap(),
1786 ParsedInstructionEnum {
1787 instruction_type: "uiAmountToAmount".to_string(),
1788 info: json!({
1789 "mint": mint_pubkey.to_string(),
1790 "uiAmount": "42.42",
1791 })
1792 }
1793 );
1794 }
1795
1796 #[test]
1797 fn test_parse_token_v3() {
1798 test_parse_token(&spl_token_interface::id());
1799 }
1800
1801 #[test]
1802 fn test_parse_token_2022() {
1803 test_parse_token(&spl_token_2022_interface::id());
1804 }
1805
1806 #[test]
1807 fn test_create_native_mint() {
1808 let payer = Pubkey::new_unique();
1809 let create_native_mint_ix =
1810 create_native_mint(&spl_token_2022_interface::id(), &payer).unwrap();
1811 let message = Message::new(&[create_native_mint_ix], None);
1812 let compiled_instruction = &message.instructions[0];
1813 assert_eq!(
1814 parse_token(
1815 compiled_instruction,
1816 &AccountKeys::new(&message.account_keys, None)
1817 )
1818 .unwrap(),
1819 ParsedInstructionEnum {
1820 instruction_type: "createNativeMint".to_string(),
1821 info: json!({
1822 "payer": payer.to_string(),
1823 "nativeMint": spl_token_2022_interface::native_mint::id().to_string(),
1824 "systemProgram": solana_sdk_ids::system_program::id().to_string(),
1825 })
1826 }
1827 );
1828 }
1829
1830 fn test_token_ix_not_enough_keys(program_id: &Pubkey) {
1831 let keys: Vec<Pubkey> = repeat_with(solana_pubkey::new_rand).take(10).collect();
1832
1833 let initialize_mint_ix =
1835 initialize_mint(program_id, &keys[0], &keys[1], Some(&keys[2]), 2).unwrap();
1836 let mut message = Message::new(&[initialize_mint_ix], None);
1837 let compiled_instruction = &mut message.instructions[0];
1838 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1839 compiled_instruction.accounts =
1840 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1841 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1842
1843 let initialize_mint_ix = initialize_mint(program_id, &keys[0], &keys[1], None, 2).unwrap();
1844 let mut message = Message::new(&[initialize_mint_ix], None);
1845 let compiled_instruction = &mut message.instructions[0];
1846 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1847 compiled_instruction.accounts =
1848 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1849 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1850
1851 let initialize_mint_ix =
1853 initialize_mint2(program_id, &keys[0], &keys[1], Some(&keys[2]), 2).unwrap();
1854 let mut message = Message::new(&[initialize_mint_ix], None);
1855 let compiled_instruction = &mut message.instructions[0];
1856 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..0], None)).is_err());
1857 compiled_instruction.accounts =
1858 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1859 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1860
1861 let initialize_account_ix =
1863 initialize_account(program_id, &keys[0], &keys[1], &keys[2]).unwrap();
1864 let mut message = Message::new(&[initialize_account_ix], None);
1865 let compiled_instruction = &mut message.instructions[0];
1866 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
1867 compiled_instruction.accounts =
1868 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1869 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1870
1871 let initialize_account_ix =
1873 initialize_account2(program_id, &keys[0], &keys[1], &keys[3]).unwrap();
1874 let mut message = Message::new(&[initialize_account_ix], None);
1875 let compiled_instruction = &mut message.instructions[0];
1876 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1877 compiled_instruction.accounts =
1878 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1879 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1880
1881 let initialize_account_ix =
1883 initialize_account3(program_id, &keys[0], &keys[1], &keys[2]).unwrap();
1884 let mut message = Message::new(&[initialize_account_ix], None);
1885 let compiled_instruction = &mut message.instructions[0];
1886 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1887 compiled_instruction.accounts =
1888 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1889 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1890
1891 let initialize_multisig_ix =
1893 initialize_multisig(program_id, &keys[0], &[&keys[1], &keys[2], &keys[3]], 2).unwrap();
1894 let mut message = Message::new(&[initialize_multisig_ix], None);
1895 let compiled_instruction = &mut message.instructions[0];
1896 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
1897 compiled_instruction.accounts =
1898 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1899 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1900
1901 let initialize_multisig_ix =
1903 initialize_multisig2(program_id, &keys[0], &[&keys[1], &keys[2], &keys[3]], 2).unwrap();
1904 let mut message = Message::new(&[initialize_multisig_ix], None);
1905 let compiled_instruction = &mut message.instructions[0];
1906 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
1907 compiled_instruction.accounts =
1908 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1909 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1910
1911 #[allow(deprecated)]
1913 let transfer_ix = transfer(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1914 let mut message = Message::new(&[transfer_ix], None);
1915 let compiled_instruction = &mut message.instructions[0];
1916 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1917 compiled_instruction.accounts =
1918 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1919 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1920
1921 #[allow(deprecated)]
1922 let transfer_ix = transfer(
1923 program_id,
1924 &keys[2],
1925 &keys[3],
1926 &keys[4],
1927 &[&keys[0], &keys[1]],
1928 42,
1929 )
1930 .unwrap();
1931 let mut message = Message::new(&[transfer_ix], None);
1932 let compiled_instruction = &mut message.instructions[0];
1933 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
1934 compiled_instruction.accounts =
1935 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1936 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1937
1938 let approve_ix = approve(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1940 let mut message = Message::new(&[approve_ix], None);
1941 let compiled_instruction = &mut message.instructions[0];
1942 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1943 compiled_instruction.accounts =
1944 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1945 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1946
1947 let approve_ix = approve(
1948 program_id,
1949 &keys[2],
1950 &keys[3],
1951 &keys[4],
1952 &[&keys[0], &keys[1]],
1953 42,
1954 )
1955 .unwrap();
1956 let mut message = Message::new(&[approve_ix], None);
1957 let compiled_instruction = &mut message.instructions[0];
1958 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..4], None)).is_err());
1959 compiled_instruction.accounts =
1960 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
1961 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1962
1963 let revoke_ix = revoke(program_id, &keys[1], &keys[0], &[]).unwrap();
1965 let mut message = Message::new(&[revoke_ix], None);
1966 let compiled_instruction = &mut message.instructions[0];
1967 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1968 compiled_instruction.accounts =
1969 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1970 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1971
1972 let set_authority_ix = set_authority(
1974 program_id,
1975 &keys[1],
1976 Some(&keys[2]),
1977 AuthorityType::FreezeAccount,
1978 &keys[0],
1979 &[],
1980 )
1981 .unwrap();
1982 let mut message = Message::new(&[set_authority_ix], None);
1983 let compiled_instruction = &mut message.instructions[0];
1984 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..1], None)).is_err());
1985 compiled_instruction.accounts =
1986 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1987 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1988
1989 let mint_to_ix = mint_to(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
1991 let mut message = Message::new(&[mint_to_ix], None);
1992 let compiled_instruction = &mut message.instructions[0];
1993 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
1994 compiled_instruction.accounts =
1995 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
1996 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
1997
1998 let burn_ix = burn(program_id, &keys[1], &keys[2], &keys[0], &[], 42).unwrap();
2000 let mut message = Message::new(&[burn_ix], None);
2001 let compiled_instruction = &mut message.instructions[0];
2002 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2003 compiled_instruction.accounts =
2004 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2005 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2006
2007 let close_account_ix =
2009 close_account(program_id, &keys[1], &keys[2], &keys[0], &[]).unwrap();
2010 let mut message = Message::new(&[close_account_ix], None);
2011 let compiled_instruction = &mut message.instructions[0];
2012 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2013 compiled_instruction.accounts =
2014 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2015 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2016
2017 let freeze_account_ix =
2019 freeze_account(program_id, &keys[1], &keys[2], &keys[0], &[]).unwrap();
2020 let mut message = Message::new(&[freeze_account_ix], None);
2021 let compiled_instruction = &mut message.instructions[0];
2022 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2023 compiled_instruction.accounts =
2024 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2025 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2026
2027 let thaw_account_ix = thaw_account(program_id, &keys[1], &keys[2], &keys[0], &[]).unwrap();
2029 let mut message = Message::new(&[thaw_account_ix], None);
2030 let compiled_instruction = &mut message.instructions[0];
2031 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2032 compiled_instruction.accounts =
2033 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2034 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2035
2036 let transfer_ix = transfer_checked(
2038 program_id,
2039 &keys[1],
2040 &keys[2],
2041 &keys[3],
2042 &keys[0],
2043 &[],
2044 42,
2045 2,
2046 )
2047 .unwrap();
2048 let mut message = Message::new(&[transfer_ix], None);
2049 let compiled_instruction = &mut message.instructions[0];
2050 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
2051 compiled_instruction.accounts =
2052 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2053 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2054
2055 let transfer_ix = transfer_checked(
2056 program_id,
2057 &keys[2],
2058 &keys[3],
2059 &keys[4],
2060 &keys[5],
2061 &[&keys[0], &keys[1]],
2062 42,
2063 2,
2064 )
2065 .unwrap();
2066 let mut message = Message::new(&[transfer_ix], None);
2067 let compiled_instruction = &mut message.instructions[0];
2068 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..5], None)).is_err());
2069 compiled_instruction.accounts =
2070 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
2071 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2072
2073 let approve_ix = approve_checked(
2075 program_id,
2076 &keys[1],
2077 &keys[2],
2078 &keys[3],
2079 &keys[0],
2080 &[],
2081 42,
2082 2,
2083 )
2084 .unwrap();
2085 let mut message = Message::new(&[approve_ix], None);
2086 let compiled_instruction = &mut message.instructions[0];
2087 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..3], None)).is_err());
2088 compiled_instruction.accounts =
2089 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2090 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2091
2092 let approve_ix = approve_checked(
2093 program_id,
2094 &keys[2],
2095 &keys[3],
2096 &keys[4],
2097 &keys[5],
2098 &[&keys[0], &keys[1]],
2099 42,
2100 2,
2101 )
2102 .unwrap();
2103 let mut message = Message::new(&[approve_ix], None);
2104 let compiled_instruction = &mut message.instructions[0];
2105 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..5], None)).is_err());
2106 compiled_instruction.accounts =
2107 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 3].to_vec();
2108 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2109
2110 let mint_to_ix =
2112 mint_to_checked(program_id, &keys[1], &keys[2], &keys[0], &[], 42, 2).unwrap();
2113 let mut message = Message::new(&[mint_to_ix], None);
2114 let compiled_instruction = &mut message.instructions[0];
2115 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2116 compiled_instruction.accounts =
2117 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2118 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2119
2120 let burn_ix = burn_checked(program_id, &keys[1], &keys[2], &keys[0], &[], 42, 2).unwrap();
2122 let mut message = Message::new(&[burn_ix], None);
2123 let compiled_instruction = &mut message.instructions[0];
2124 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys[0..2], None)).is_err());
2125 compiled_instruction.accounts =
2126 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2127 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2128
2129 let sync_native_ix = sync_native(program_id, &keys[0]).unwrap();
2131 let mut message = Message::new(&[sync_native_ix], None);
2132 let compiled_instruction = &mut message.instructions[0];
2133 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2134 compiled_instruction.accounts =
2135 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2136 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2137
2138 let init_immutable_owner_ix = initialize_immutable_owner(program_id, &keys[0]).unwrap();
2140 let mut message = Message::new(&[init_immutable_owner_ix], None);
2141 let compiled_instruction = &mut message.instructions[0];
2142 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2143 compiled_instruction.accounts =
2144 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2145 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2146
2147 let get_account_data_size_ix = get_account_data_size(program_id, &keys[0], &[]).unwrap();
2149 let mut message = Message::new(&[get_account_data_size_ix], None);
2150 let compiled_instruction = &mut message.instructions[0];
2151 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2152 compiled_instruction.accounts =
2153 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2154 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2155
2156 let amount_to_ui_amount_ix = amount_to_ui_amount(program_id, &keys[0], 4242).unwrap();
2158 let mut message = Message::new(&[amount_to_ui_amount_ix], None);
2159 let compiled_instruction = &mut message.instructions[0];
2160 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2161 compiled_instruction.accounts =
2162 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2163 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2164
2165 let ui_amount_to_amount_ix = ui_amount_to_amount(program_id, &keys[0], "42.42").unwrap();
2167 let mut message = Message::new(&[ui_amount_to_amount_ix], None);
2168 let compiled_instruction = &mut message.instructions[0];
2169 assert!(parse_token(compiled_instruction, &AccountKeys::new(&[], None)).is_err());
2170 compiled_instruction.accounts =
2171 compiled_instruction.accounts[0..compiled_instruction.accounts.len() - 1].to_vec();
2172 assert!(parse_token(compiled_instruction, &AccountKeys::new(&keys, None)).is_err());
2173 }
2174
2175 #[test]
2176 fn test_not_enough_keys_token_v3() {
2177 test_token_ix_not_enough_keys(&spl_token_interface::id());
2178 }
2179
2180 #[test]
2181 fn test_not_enough_keys_token_2022() {
2182 test_token_ix_not_enough_keys(&spl_token_2022_interface::id());
2183 }
2184}