1use crate::utils::*;
2use borsh::ser::BorshSerialize;
3use mpl_token_metadata::{
4 id,
5 instruction::{self, CreateMasterEditionArgs, MetadataInstruction},
6 state::{EDITION, PREFIX},
7};
8use solana_program::{
9 borsh::try_from_slice_unchecked,
10 instruction::{AccountMeta, Instruction},
11 sysvar,
12};
13use solana_program_test::*;
14use solana_sdk::{
15 pubkey::Pubkey,
16 signature::{Keypair, Signer},
17 transaction::Transaction,
18};
19
20#[derive(Debug)]
21pub struct MasterEditionV2 {
22 pub pubkey: Pubkey,
23 pub metadata_pubkey: Pubkey,
24 pub mint_pubkey: Pubkey,
25}
26
27impl MasterEditionV2 {
28 pub fn new(metadata: &Metadata) -> Self {
29 let program_id = id();
30 let mint_pubkey = metadata.mint.pubkey();
31
32 let master_edition_seeds = &[
33 PREFIX.as_bytes(),
34 program_id.as_ref(),
35 mint_pubkey.as_ref(),
36 EDITION.as_bytes(),
37 ];
38 let (pubkey, _) = Pubkey::find_program_address(master_edition_seeds, &id());
39
40 MasterEditionV2 {
41 pubkey,
42 metadata_pubkey: metadata.pubkey,
43 mint_pubkey,
44 }
45 }
46
47 pub async fn get_data(
48 &self,
49 context: &mut ProgramTestContext,
50 ) -> mpl_token_metadata::state::MasterEditionV2 {
51 let account = get_account(context, &self.pubkey).await;
52 try_from_slice_unchecked(&account.data).unwrap()
53 }
54
55 pub async fn get_data_from_account(
56 context: &mut ProgramTestContext,
57 pubkey: &Pubkey,
58 ) -> mpl_token_metadata::state::MasterEditionV2 {
59 let account = get_account(context, pubkey).await;
60 try_from_slice_unchecked(&account.data).unwrap()
61 }
62
63 pub async fn create_with_invalid_token_program(
64 &self,
65 context: &mut ProgramTestContext,
66 max_supply: Option<u64>,
67 ) -> Result<(), BanksClientError> {
68 let fake_token_program = Keypair::new();
69
70 let fake_instruction = Instruction {
71 program_id: mpl_token_metadata::id(),
72 accounts: vec![
73 AccountMeta::new(self.pubkey, false),
74 AccountMeta::new(self.mint_pubkey, false),
75 AccountMeta::new_readonly(context.payer.pubkey(), true),
76 AccountMeta::new_readonly(context.payer.pubkey(), true),
77 AccountMeta::new_readonly(context.payer.pubkey(), true),
78 AccountMeta::new_readonly(self.metadata_pubkey, false),
79 AccountMeta::new_readonly(fake_token_program.pubkey(), false),
80 AccountMeta::new_readonly(solana_program::system_program::id(), false),
81 AccountMeta::new_readonly(sysvar::rent::id(), false),
82 ],
83 data: MetadataInstruction::CreateMasterEdition(CreateMasterEditionArgs { max_supply })
84 .try_to_vec()
85 .unwrap(),
86 };
87
88 let tx = Transaction::new_signed_with_payer(
89 &[fake_instruction],
90 Some(&context.payer.pubkey()),
91 &[&context.payer],
92 context.last_blockhash,
93 );
94
95 context.banks_client.process_transaction(tx).await
96 }
97
98 pub async fn create(
99 &self,
100 context: &mut ProgramTestContext,
101 max_supply: Option<u64>,
102 ) -> Result<(), BanksClientError> {
103 let tx = Transaction::new_signed_with_payer(
104 &[instruction::create_master_edition(
105 id(),
106 self.pubkey,
107 self.mint_pubkey,
108 context.payer.pubkey(),
109 context.payer.pubkey(),
110 self.metadata_pubkey,
111 context.payer.pubkey(),
112 max_supply,
113 )],
114 Some(&context.payer.pubkey()),
115 &[&context.payer],
116 context.last_blockhash,
117 );
118
119 context.banks_client.process_transaction(tx).await
120 }
121
122 pub async fn create_v3(
123 &self,
124 context: &mut ProgramTestContext,
125 max_supply: Option<u64>,
126 ) -> Result<(), BanksClientError> {
127 let tx = Transaction::new_signed_with_payer(
128 &[instruction::create_master_edition_v3(
129 id(),
130 self.pubkey,
131 self.mint_pubkey,
132 context.payer.pubkey(),
133 context.payer.pubkey(),
134 self.metadata_pubkey,
135 context.payer.pubkey(),
136 max_supply,
137 )],
138 Some(&context.payer.pubkey()),
139 &[&context.payer],
140 context.last_blockhash,
141 );
142
143 context.banks_client.process_transaction(tx).await
144 }
145}