1use crate::{solana::create_associated_token_account, utils::*};
2use mpl_token_metadata::{
3 id, instruction,
4 state::{Collection, Creator, Data, DataV2, Uses, PREFIX},
5};
6use solana_program::borsh::try_from_slice_unchecked;
7use solana_program_test::*;
8use solana_sdk::{
9 pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, transaction::Transaction,
10};
11
12#[derive(Debug)]
13pub struct Metadata {
14 pub mint: Keypair,
15 pub pubkey: Pubkey,
16 pub token: Keypair,
17}
18
19impl Default for Metadata {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl Metadata {
26 pub fn new() -> Self {
27 let mint = Keypair::new();
28 let mint_pubkey = mint.pubkey();
29 let program_id = id();
30
31 let metadata_seeds = &[PREFIX.as_bytes(), program_id.as_ref(), mint_pubkey.as_ref()];
32 let (pubkey, _) = Pubkey::find_program_address(metadata_seeds, &id());
33
34 Metadata {
35 mint,
36 pubkey,
37 token: Keypair::new(),
38 }
39 }
40
41 pub async fn get_data(
42 &self,
43 context: &mut ProgramTestContext,
44 ) -> mpl_token_metadata::state::Metadata {
45 let account = get_account(context, &self.pubkey).await;
46 try_from_slice_unchecked(&account.data).unwrap()
47 }
48
49 pub async fn create(
50 &self,
51 context: &mut ProgramTestContext,
52 name: String,
53 symbol: String,
54 uri: String,
55 creators: Option<Vec<Creator>>,
56 seller_fee_basis_points: u16,
57 is_mutable: bool,
58 amount: u64,
59 ) -> Result<(), BanksClientError> {
60 create_mint(context, &self.mint, &context.payer.pubkey(), None).await?;
61
62 let token = create_associated_token_account(context, &self.token, &self.mint.pubkey())
63 .await
64 .unwrap();
65 mint_tokens(
66 context,
67 &self.mint.pubkey(),
68 &token,
69 amount,
70 &context.payer.pubkey(),
71 None,
72 )
73 .await?;
74
75 let tx = Transaction::new_signed_with_payer(
76 &[instruction::create_metadata_accounts(
77 id(),
78 self.pubkey,
79 self.mint.pubkey(),
80 context.payer.pubkey(),
81 context.payer.pubkey(),
82 context.payer.pubkey(),
83 name,
84 symbol,
85 uri,
86 creators,
87 seller_fee_basis_points,
88 false,
89 is_mutable,
90 )],
91 Some(&context.payer.pubkey()),
92 &[&context.payer],
93 context.last_blockhash,
94 );
95
96 context.banks_client.process_transaction(tx).await
97 }
98
99 pub async fn create_v2(
100 &self,
101 context: &mut ProgramTestContext,
102 name: String,
103 symbol: String,
104 uri: String,
105 creators: Option<Vec<Creator>>,
106 seller_fee_basis_points: u16,
107 is_mutable: bool,
108 collection: Option<Collection>,
109 uses: Option<Uses>,
110 ) -> Result<(), BanksClientError> {
111 create_mint(context, &self.mint, &context.payer.pubkey(), None).await?;
112 create_token_account(
113 context,
114 &self.token,
115 &self.mint.pubkey(),
116 &context.payer.pubkey(),
117 )
118 .await?;
119 mint_tokens(
120 context,
121 &self.mint.pubkey(),
122 &self.token.pubkey(),
123 1,
124 &context.payer.pubkey(),
125 None,
126 )
127 .await?;
128
129 let tx = Transaction::new_signed_with_payer(
130 &[instruction::create_metadata_accounts_v2(
131 id(),
132 self.pubkey,
133 self.mint.pubkey(),
134 context.payer.pubkey(),
135 context.payer.pubkey(),
136 context.payer.pubkey(),
137 name,
138 symbol,
139 uri,
140 creators,
141 seller_fee_basis_points,
142 false,
143 is_mutable,
144 collection,
145 uses,
146 )],
147 Some(&context.payer.pubkey()),
148 &[&context.payer],
149 context.last_blockhash,
150 );
151
152 context.banks_client.process_transaction(tx).await
153 }
154
155 pub async fn update_primary_sale_happened_via_token(
156 &self,
157 context: &mut ProgramTestContext,
158 ) -> Result<(), BanksClientError> {
159 let tx = Transaction::new_signed_with_payer(
160 &[instruction::update_primary_sale_happened_via_token(
161 id(),
162 self.pubkey,
163 context.payer.pubkey(),
164 self.token.pubkey(),
165 )],
166 Some(&context.payer.pubkey()),
167 &[&context.payer],
168 context.last_blockhash,
169 );
170
171 context.banks_client.process_transaction(tx).await
172 }
173
174 pub async fn update(
175 &self,
176 context: &mut ProgramTestContext,
177 name: String,
178 symbol: String,
179 uri: String,
180 creators: Option<Vec<Creator>>,
181 seller_fee_basis_points: u16,
182 ) -> Result<(), BanksClientError> {
183 let tx = Transaction::new_signed_with_payer(
184 &[instruction::update_metadata_accounts(
185 id(),
186 self.pubkey,
187 context.payer.pubkey(),
188 None,
189 Some(Data {
190 name,
191 symbol,
192 uri,
193 creators,
194 seller_fee_basis_points,
195 }),
196 None,
197 )],
198 Some(&context.payer.pubkey()),
199 &[&context.payer],
200 context.last_blockhash,
201 );
202
203 context.banks_client.process_transaction(tx).await
204 }
205
206 pub async fn update_v2(
207 &self,
208 context: &mut ProgramTestContext,
209 name: String,
210 symbol: String,
211 uri: String,
212 creators: Option<Vec<Creator>>,
213 seller_fee_basis_points: u16,
214 is_mutable: bool,
215 collection: Option<Collection>,
216 uses: Option<Uses>,
217 ) -> Result<(), BanksClientError> {
218 let tx = Transaction::new_signed_with_payer(
219 &[instruction::update_metadata_accounts_v2(
220 id(),
221 self.pubkey,
222 context.payer.pubkey(),
223 None,
224 Some(DataV2 {
225 name,
226 symbol,
227 uri,
228 creators,
229 seller_fee_basis_points,
230 collection,
231 uses,
232 }),
233 None,
234 Some(is_mutable),
235 )],
236 Some(&context.payer.pubkey()),
237 &[&context.payer],
238 context.last_blockhash,
239 );
240
241 context.banks_client.process_transaction(tx).await
242 }
243
244 pub async fn verify_collection(
245 &self,
246 context: &mut ProgramTestContext,
247 collection: Pubkey,
248 collection_authority: Keypair,
249 collection_mint: Pubkey,
250 collection_master_edition_account: Pubkey,
251 collection_authority_record: Option<Pubkey>,
252 ) -> Result<(), BanksClientError> {
253 let tx = Transaction::new_signed_with_payer(
254 &[instruction::verify_collection(
255 id(),
256 self.pubkey,
257 collection_authority.pubkey(),
258 context.payer.pubkey(),
259 collection_mint,
260 collection,
261 collection_master_edition_account,
262 collection_authority_record,
263 )],
264 Some(&context.payer.pubkey()),
265 &[&context.payer, &collection_authority],
266 context.last_blockhash,
267 );
268
269 context.banks_client.process_transaction(tx).await
270 }
271
272 pub async fn unverify_collection(
273 &self,
274 context: &mut ProgramTestContext,
275 collection: Pubkey,
276 collection_authority: Keypair,
277 collection_mint: Pubkey,
278 collection_master_edition_account: Pubkey,
279 collection_authority_record: Option<Pubkey>,
280 ) -> Result<(), BanksClientError> {
281 let tx = Transaction::new_signed_with_payer(
282 &[instruction::unverify_collection(
283 id(),
284 self.pubkey,
285 collection_authority.pubkey(),
286 collection_mint,
287 collection,
288 collection_master_edition_account,
289 collection_authority_record,
290 )],
291 Some(&context.payer.pubkey()),
292 &[&context.payer, &collection_authority],
293 context.last_blockhash,
294 );
295
296 context.banks_client.process_transaction(tx).await
297 }
298}