1use super::*;
2use crate::{
3 assertions::{
4 collection::assert_collection_update_is_valid, metadata::assert_data_valid,
5 uses::assert_valid_use,
6 },
7 instruction::{CollectionDetailsToggle, CollectionToggle, RuleSetToggle, UpdateArgs},
8 utils::{clean_write_metadata, puff_out_data_fields},
9};
10
11pub const MAX_NAME_LENGTH: usize = 32;
12
13pub const MAX_SYMBOL_LENGTH: usize = 10;
14
15pub const MAX_URI_LENGTH: usize = 200;
16
17pub const MAX_METADATA_LEN: usize = 1 + 32 + 32 + MAX_DATA_SIZE
21+ 1 + 1 + 9 + 2 + 34 + 18 + 10 + 33 + 75; pub const MAX_DATA_SIZE: usize = 4
32 + MAX_NAME_LENGTH
33 + 4
34 + MAX_SYMBOL_LENGTH
35 + 4
36 + MAX_URI_LENGTH
37 + 2
38 + 1
39 + 4
40 + MAX_CREATOR_LIMIT * MAX_CREATOR_LEN;
41
42#[macro_export]
43macro_rules! metadata_seeds {
44 ($mint:expr) => {{
45 let path = vec!["metadata".as_bytes(), $crate::ID.as_ref(), $mint.as_ref()];
46 let (_, bump) = Pubkey::find_program_address(&path, &$crate::ID);
47 &[
48 "metadata".as_bytes(),
49 $crate::ID.as_ref(),
50 $mint.as_ref(),
51 &[bump],
52 ]
53 }};
54}
55
56#[repr(C)]
57#[cfg_attr(feature = "serde-feature", derive(Serialize, Deserialize))]
58#[derive(Clone, BorshSerialize, Debug, PartialEq, Eq, ShankAccount)]
59pub struct Metadata {
60 pub key: Key,
62 #[cfg_attr(feature = "serde-feature", serde(with = "As::<DisplayFromStr>"))]
64 pub update_authority: Pubkey,
65 #[cfg_attr(feature = "serde-feature", serde(with = "As::<DisplayFromStr>"))]
67 pub mint: Pubkey,
68 pub data: Data,
70 pub primary_sale_happened: bool,
72 pub is_mutable: bool,
74 pub edition_nonce: Option<u8>,
76 pub token_standard: Option<TokenStandard>,
78 pub collection: Option<Collection>,
80 pub uses: Option<Uses>,
82 pub collection_details: Option<CollectionDetails>,
84 pub programmable_config: Option<ProgrammableConfig>,
86}
87
88impl Metadata {
89 pub fn save(&self, data: &mut [u8]) -> Result<(), BorshError> {
90 let mut bytes = Vec::with_capacity(MAX_METADATA_LEN);
91 BorshSerialize::serialize(&self, &mut bytes)?;
92 data[..bytes.len()].copy_from_slice(&bytes);
93 Ok(())
94 }
95
96 pub(crate) fn update_v1<'a>(
97 &mut self,
98 args: UpdateArgs,
99 update_authority: &AccountInfo<'a>,
100 metadata: &AccountInfo<'a>,
101 token: Option<TokenAccount>,
102 token_standard: TokenStandard,
103 ) -> ProgramResult {
104 self.token_standard = Some(token_standard);
106
107 match &args {
109 UpdateArgs::V1 {
110 uses,
111 collection_details,
112 ..
113 }
114 | UpdateArgs::AsUpdateAuthorityV2 {
115 uses,
116 collection_details,
117 ..
118 } => {
119 if uses.is_some() {
120 let uses_option = uses.clone().to_option();
121 assert_valid_use(&uses_option, &self.uses)?;
123 self.uses = uses_option;
124 }
125
126 if let CollectionDetailsToggle::Set(collection_details) = collection_details {
127 if self.collection_details.is_some() {
129 return Err(MetadataError::SizedCollection.into());
130 }
131
132 self.collection_details = Some(collection_details.clone());
133 }
134 }
135 _ => (),
136 }
137
138 match &args {
142 UpdateArgs::V1 { data, .. }
143 | UpdateArgs::AsUpdateAuthorityV2 { data, .. }
144 | UpdateArgs::AsDataDelegateV2 { data, .. }
145 | UpdateArgs::AsDataItemDelegateV2 { data, .. } => {
146 if let Some(data) = data {
147 if !self.is_mutable {
148 return Err(MetadataError::DataIsImmutable.into());
149 }
150
151 assert_data_valid(
152 data,
153 update_authority.key,
154 self,
155 false,
156 update_authority.is_signer,
157 )?;
158 self.data = data.clone();
159 }
160 }
161 _ => (),
162 }
163
164 match &args {
166 UpdateArgs::V1 {
167 new_update_authority,
168 primary_sale_happened,
169 is_mutable,
170 ..
171 }
172 | UpdateArgs::AsUpdateAuthorityV2 {
173 new_update_authority,
174 primary_sale_happened,
175 is_mutable,
176 ..
177 }
178 | UpdateArgs::AsAuthorityItemDelegateV2 {
179 new_update_authority,
180 primary_sale_happened,
181 is_mutable,
182 ..
183 } => {
184 if let Some(authority) = new_update_authority {
185 self.update_authority = *authority;
186 }
187
188 if let Some(primary_sale) = primary_sale_happened {
189 if *primary_sale || !self.primary_sale_happened {
191 self.primary_sale_happened = *primary_sale
192 } else {
193 return Err(MetadataError::PrimarySaleCanOnlyBeFlippedToTrue.into());
194 }
195 }
196
197 if let Some(mutable) = is_mutable {
198 if !mutable || self.is_mutable {
200 self.is_mutable = *mutable
201 } else {
202 return Err(MetadataError::IsMutableCanOnlyBeFlippedToFalse.into());
203 }
204 }
205 }
206 _ => (),
207 }
208
209 match &args {
211 UpdateArgs::V1 { collection, .. }
212 | UpdateArgs::AsUpdateAuthorityV2 { collection, .. }
213 | UpdateArgs::AsCollectionDelegateV2 { collection, .. }
214 | UpdateArgs::AsCollectionItemDelegateV2 { collection, .. } => match collection {
215 CollectionToggle::Set(_) => {
219 let collection_option = collection.clone().to_option();
220 assert_collection_update_is_valid(false, &self.collection, &collection_option)?;
221 self.collection = collection_option;
222 }
223 CollectionToggle::Clear => {
224 if let Some(current_collection) = self.collection.as_ref() {
225 if current_collection.verified {
227 return Err(MetadataError::CannotUpdateVerifiedCollection.into());
228 }
229 self.collection = None;
231 }
232 }
233 CollectionToggle::None => { }
234 },
235 _ => (),
236 };
237
238 match &args {
240 UpdateArgs::V1 { rule_set, .. }
241 | UpdateArgs::AsUpdateAuthorityV2 { rule_set, .. }
242 | UpdateArgs::AsProgrammableConfigDelegateV2 { rule_set, .. }
243 | UpdateArgs::AsProgrammableConfigItemDelegateV2 { rule_set, .. } => {
244 if matches!(rule_set, RuleSetToggle::Clear | RuleSetToggle::Set(_)) {
247 if token_standard != TokenStandard::ProgrammableNonFungible {
248 return Err(MetadataError::InvalidTokenStandard.into());
249 }
250
251 let token = token.ok_or(MetadataError::MissingTokenAccount)?;
253
254 if token.delegate.is_some() {
256 return Err(MetadataError::CannotUpdateAssetWithDelegate.into());
257 }
258
259 self.programmable_config =
260 rule_set
261 .clone()
262 .to_option()
263 .map(|rule_set| ProgrammableConfig::V1 {
264 rule_set: Some(rule_set),
265 });
266 }
267 }
268 _ => (),
269 };
270
271 puff_out_data_fields(self);
273 clean_write_metadata(self, metadata)
274 }
275
276 pub fn into_asset_data(self) -> AssetData {
277 let mut asset_data = AssetData::new(
278 self.token_standard.unwrap_or(TokenStandard::NonFungible),
279 self.data.name,
280 self.data.symbol,
281 self.data.uri,
282 );
283 asset_data.seller_fee_basis_points = self.data.seller_fee_basis_points;
284 asset_data.creators = self.data.creators;
285 asset_data.primary_sale_happened = self.primary_sale_happened;
286 asset_data.is_mutable = self.is_mutable;
287 asset_data.collection = self.collection;
288 asset_data.uses = self.uses;
289 asset_data.collection_details = self.collection_details;
290 asset_data.rule_set =
291 if let Some(ProgrammableConfig::V1 { rule_set }) = self.programmable_config {
292 rule_set
293 } else {
294 None
295 };
296
297 asset_data
298 }
299}
300
301impl Default for Metadata {
302 fn default() -> Self {
303 Metadata {
304 key: Key::MetadataV1,
305 update_authority: Pubkey::default(),
306 mint: Pubkey::default(),
307 data: Data::default(),
308 primary_sale_happened: false,
309 is_mutable: false,
310 edition_nonce: None,
311 token_standard: None,
312 collection: None,
313 uses: None,
314 collection_details: None,
315 programmable_config: None,
316 }
317 }
318}
319
320impl TokenMetadataAccount for Metadata {
321 fn key() -> Key {
322 Key::MetadataV1
323 }
324
325 fn size() -> usize {
326 MAX_METADATA_LEN
327 }
328}
329
330impl borsh::de::BorshDeserialize for Metadata {
334 fn deserialize(buf: &mut &[u8]) -> ::core::result::Result<Self, BorshError> {
335 let md = meta_deser_unchecked(buf)?;
336 Ok(md)
337 }
338}
339
340#[repr(C)]
341#[cfg_attr(feature = "serde-feature", derive(Serialize, Deserialize))]
342#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
343pub enum PrintSupply {
345 Zero,
347 Limited(u64),
349 Unlimited,
351}
352
353impl PrintSupply {
354 pub fn to_option(&self) -> Option<u64> {
356 match self {
357 PrintSupply::Zero => Some(0),
358 PrintSupply::Limited(supply) => Some(*supply),
359 PrintSupply::Unlimited => None,
360 }
361 }
362}
363
364#[repr(C)]
366#[cfg_attr(feature = "serde-feature", derive(Serialize, Deserialize))]
367#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
368pub enum ProgrammableConfig {
369 V1 {
370 #[cfg_attr(
372 feature = "serde-feature",
373 serde(
374 deserialize_with = "deser_option_pubkey",
375 serialize_with = "ser_option_pubkey"
376 )
377 )]
378 rule_set: Option<Pubkey>,
379 },
380}
381
382#[cfg(test)]
383mod tests {
384 use borsh::{BorshDeserialize, BorshSerialize};
385 use solana_program::account_info::AccountInfo;
386 use solana_sdk::{signature::Keypair, signer::Signer};
387
388 use crate::{
389 error::MetadataError,
390 state::{
391 CollectionAuthorityRecord, Edition, EditionMarker, Key, MasterEditionV2, Metadata,
392 TokenMetadataAccount, UseAuthorityRecord, MAX_METADATA_LEN,
393 },
394 utils::metadata::tests::{expected_pesky_metadata, pesky_data},
395 ID,
396 };
397
398 fn pad_metadata_length(metadata: &mut Vec<u8>) {
399 let padding_length = MAX_METADATA_LEN - metadata.len();
400 metadata.extend(vec![0; padding_length]);
401 }
402
403 #[test]
404 fn successfully_deserialize_corrupted_metadata() {
405 let expected_metadata = expected_pesky_metadata();
408 let mut corrupted_data = pesky_data();
409
410 let metadata = Metadata::deserialize(&mut corrupted_data).unwrap();
411
412 assert_eq!(metadata, expected_metadata);
413 }
414
415 #[test]
416 fn successfully_deserialize_metadata() {
417 let expected_metadata = expected_pesky_metadata();
418
419 let mut buf = Vec::new();
420 expected_metadata.serialize(&mut buf).unwrap();
421 pad_metadata_length(&mut buf);
422
423 let pubkey = Keypair::new().pubkey();
424 let owner = &ID;
425 let mut lamports = 1_000_000_000;
426 let mut data = buf.clone();
427
428 let md_account_info = AccountInfo::new(
429 &pubkey,
430 false,
431 true,
432 &mut lamports,
433 &mut data,
434 owner,
435 false,
436 1_000_000_000,
437 );
438
439 let md = Metadata::from_account_info(&md_account_info).unwrap();
440 assert_eq!(md.key, Key::MetadataV1);
441 assert_eq!(md, expected_metadata);
442 }
443
444 #[test]
445 fn fail_to_deserialize_metadata_with_wrong_owner() {
446 let expected_metadata = expected_pesky_metadata();
447
448 let mut buf = Vec::new();
449 expected_metadata.serialize(&mut buf).unwrap();
450 pad_metadata_length(&mut buf);
451
452 let pubkey = Keypair::new().pubkey();
453 let invalid_owner = Keypair::new().pubkey();
454 let mut lamports = 1_000_000_000;
455 let mut data = buf.clone();
456
457 let md_account_info = AccountInfo::new(
458 &pubkey,
459 false,
460 true,
461 &mut lamports,
462 &mut data,
463 &invalid_owner,
464 false,
465 1_000_000_000,
466 );
467
468 let error = Metadata::from_account_info(&md_account_info).unwrap_err();
471 assert_eq!(error, MetadataError::IncorrectOwner.into());
472 }
473
474 #[test]
475 fn fail_to_deserialize_metadata_with_wrong_size() {
476 let expected_metadata = expected_pesky_metadata();
477
478 let mut buf = Vec::new();
479 expected_metadata.serialize(&mut buf).unwrap();
480 let pubkey = Keypair::new().pubkey();
483 let owner = ID;
484 let mut lamports = 1_000_000_000;
485 let mut data = buf.clone();
486
487 let account_info = AccountInfo::new(
488 &pubkey,
489 false,
490 true,
491 &mut lamports,
492 &mut data,
493 &owner,
494 false,
495 1_000_000_000,
496 );
497
498 let error = Metadata::from_account_info(&account_info).unwrap_err();
501 assert_eq!(error, MetadataError::DataTypeMismatch.into());
502 }
503
504 #[test]
505 fn fail_to_deserialize_master_edition_into_metadata() {
506 let master_edition = MasterEditionV2 {
507 key: Key::MasterEditionV2,
508 supply: 0,
509 max_supply: Some(0),
510 };
511 let mut buf = Vec::new();
512 master_edition.serialize(&mut buf).unwrap();
513
514 let pubkey = Keypair::new().pubkey();
515 let owner = &ID;
516 let mut lamports = 1_000_000_000;
517 let mut data = buf.clone();
518
519 let account_info = AccountInfo::new(
520 &pubkey,
521 false,
522 true,
523 &mut lamports,
524 &mut data,
525 owner,
526 false,
527 1_000_000_000,
528 );
529
530 let err = Metadata::from_account_info(&account_info).unwrap_err();
531 assert_eq!(err, MetadataError::DataTypeMismatch.into());
532 }
533
534 #[test]
535 fn fail_to_deserialize_edition_into_metadata() {
536 let parent = Keypair::new().pubkey();
537 let edition = 1;
538
539 let edition = Edition {
540 key: Key::EditionV1,
541 parent,
542 edition,
543 };
544
545 let mut buf = Vec::new();
546 edition.serialize(&mut buf).unwrap();
547
548 let pubkey = Keypair::new().pubkey();
549 let owner = &ID;
550 let mut lamports = 1_000_000_000;
551 let mut data = buf.clone();
552
553 let account_info = AccountInfo::new(
554 &pubkey,
555 false,
556 true,
557 &mut lamports,
558 &mut data,
559 owner,
560 false,
561 1_000_000_000,
562 );
563
564 let err = Metadata::from_account_info(&account_info).unwrap_err();
565 assert_eq!(err, MetadataError::DataTypeMismatch.into());
566 }
567
568 #[test]
569 fn fail_to_deserialize_use_authority_record_into_metadata() {
570 let use_record = UseAuthorityRecord {
571 key: Key::UseAuthorityRecord,
572 allowed_uses: 14,
573 bump: 255,
574 };
575
576 let mut buf = Vec::new();
577 use_record.serialize(&mut buf).unwrap();
578
579 let pubkey = Keypair::new().pubkey();
580 let owner = &ID;
581 let mut lamports = 1_000_000_000;
582 let mut data = buf.clone();
583
584 let account_info = AccountInfo::new(
585 &pubkey,
586 false,
587 true,
588 &mut lamports,
589 &mut data,
590 owner,
591 false,
592 1_000_000_000,
593 );
594
595 let err = Metadata::from_account_info(&account_info).unwrap_err();
596 assert_eq!(err, MetadataError::DataTypeMismatch.into());
597 }
598
599 #[test]
600 fn fail_to_deserialize_collection_authority_record_into_metadata() {
601 let collection_record = CollectionAuthorityRecord {
602 key: Key::CollectionAuthorityRecord,
603 bump: 255,
604 update_authority: None,
605 };
606
607 let mut buf = Vec::new();
608 collection_record.serialize(&mut buf).unwrap();
609
610 let pubkey = Keypair::new().pubkey();
611 let owner = &ID;
612 let mut lamports = 1_000_000_000;
613 let mut data = buf.clone();
614
615 let account_info = AccountInfo::new(
616 &pubkey,
617 false,
618 true,
619 &mut lamports,
620 &mut data,
621 owner,
622 false,
623 1_000_000_000,
624 );
625
626 let err = Metadata::from_account_info(&account_info).unwrap_err();
627 assert_eq!(err, MetadataError::DataTypeMismatch.into());
628 }
629
630 #[test]
631 fn fail_to_deserialize_edition_marker_into_metadata() {
632 let edition_marker = EditionMarker {
633 key: Key::EditionMarker,
634 ledger: [0; 31],
635 };
636
637 let mut buf = Vec::new();
638 edition_marker.serialize(&mut buf).unwrap();
639
640 let pubkey = Keypair::new().pubkey();
641 let owner = &ID;
642 let mut lamports = 1_000_000_000;
643 let mut data = buf.clone();
644
645 let account_info = AccountInfo::new(
646 &pubkey,
647 false,
648 true,
649 &mut lamports,
650 &mut data,
651 owner,
652 false,
653 1_000_000_000,
654 );
655
656 let err = Metadata::from_account_info(&account_info).unwrap_err();
657 assert_eq!(err, MetadataError::DataTypeMismatch.into());
658 }
659}