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