mpl_token_metadata_extended_uri/
state.rs

1use crate::{deser::meta_deser, error::MetadataError, utils::try_from_slice_checked};
2use borsh::{BorshDeserialize, BorshSerialize};
3use shank::ShankAccount;
4use solana_program::{
5    account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
6    pubkey::Pubkey,
7};
8/// prefix used for PDAs to avoid certain collision attacks (https://en.wikipedia.org/wiki/Collision_attack#Chosen-prefix_collision_attack)
9pub const PREFIX: &str = "metadata";
10
11/// Used in seeds to make Edition model pda address
12pub const EDITION: &str = "edition";
13
14pub const RESERVATION: &str = "reservation";
15
16pub const USER: &str = "user";
17
18pub const BURN: &str = "burn";
19
20pub const COLLECTION_AUTHORITY: &str = "collection_authority";
21
22pub const MAX_NAME_LENGTH: usize = 32;
23
24pub const MAX_SYMBOL_LENGTH: usize = 10;
25
26pub const MAX_URI_LENGTH: usize = 5000;
27
28pub const MAX_METADATA_LEN: usize = 1 //key 
29+ 32 // update auth pubkey
30+ 32 // mint pubkey
31+ MAX_DATA_SIZE
32+ 1 // primary sale
33+ 1 // mutable
34+ 9 // nonce (pretty sure this only needs to be 2)
35+ 2 // token standard
36+ 34 // collection
37+ 18 // uses
38+ 118; // Padding
39
40pub const MAX_DATA_SIZE: usize = 4
41    + MAX_NAME_LENGTH
42    + 4
43    + MAX_SYMBOL_LENGTH
44    + 4
45    + MAX_URI_LENGTH
46    + 2
47    + 1
48    + 4
49    + MAX_CREATOR_LIMIT * MAX_CREATOR_LEN;
50
51pub const MAX_EDITION_LEN: usize = 1 + 32 + 8 + 200;
52
53// Large buffer because the older master editions have two pubkeys in them,
54// need to keep two versions same size because the conversion process actually changes the same account
55// by rewriting it.
56pub const MAX_MASTER_EDITION_LEN: usize = 1 + 9 + 8 + 264;
57
58pub const MAX_CREATOR_LIMIT: usize = 5;
59
60pub const MAX_CREATOR_LEN: usize = 32 + 1 + 1;
61
62pub const MAX_RESERVATIONS: usize = 200;
63
64// can hold up to 200 keys per reservation, note: the extra 8 is for number of elements in the vec
65pub const MAX_RESERVATION_LIST_V1_SIZE: usize = 1 + 32 + 8 + 8 + MAX_RESERVATIONS * 34 + 100;
66
67// can hold up to 200 keys per reservation, note: the extra 8 is for number of elements in the vec
68pub const MAX_RESERVATION_LIST_SIZE: usize = 1 + 32 + 8 + 8 + MAX_RESERVATIONS * 48 + 8 + 8 + 84;
69
70pub const MAX_EDITION_MARKER_SIZE: usize = 32;
71
72pub const EDITION_MARKER_BIT_SIZE: u64 = 248;
73
74pub const USE_AUTHORITY_RECORD_SIZE: usize = 18; //8 byte padding
75
76pub const COLLECTION_AUTHORITY_RECORD_SIZE: usize = 11; //10 byte padding
77
78#[repr(C)]
79#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, Copy)]
80pub enum Key {
81    Uninitialized,
82    EditionV1,
83    MasterEditionV1,
84    ReservationListV1,
85    MetadataV1,
86    ReservationListV2,
87    MasterEditionV2,
88    EditionMarker,
89    UseAuthorityRecord,
90    CollectionAuthorityRecord,
91}
92#[repr(C)]
93#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
94pub struct Data {
95    /// The name of the asset
96    pub name: String,
97    /// The symbol for the asset
98    pub symbol: String,
99    /// URI pointing to JSON representing the asset
100    pub uri: String,
101    /// Royalty basis points that goes to creators in secondary sales (0-10000)
102    pub seller_fee_basis_points: u16,
103    /// Array of creators, optional
104    pub creators: Option<Vec<Creator>>,
105}
106
107#[repr(C)]
108#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
109pub struct DataV2 {
110    /// The name of the asset
111    pub name: String,
112    /// The symbol for the asset
113    pub symbol: String,
114    /// URI pointing to JSON representing the asset
115    pub uri: String,
116    /// Royalty basis points that goes to creators in secondary sales (0-10000)
117    pub seller_fee_basis_points: u16,
118    /// Array of creators, optional
119    pub creators: Option<Vec<Creator>>,
120    /// Collection
121    pub collection: Option<Collection>,
122    /// Uses
123    pub uses: Option<Uses>,
124}
125
126impl DataV2 {
127    pub fn to_v1(&self) -> Data {
128        let ns = self.clone();
129        Data {
130            name: ns.name,
131            symbol: ns.symbol,
132            uri: ns.uri,
133            seller_fee_basis_points: ns.seller_fee_basis_points,
134            creators: ns.creators,
135        }
136    }
137}
138
139#[repr(C)]
140#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
141pub enum UseMethod {
142    Burn,
143    Multiple,
144    Single,
145}
146
147#[repr(C)]
148#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
149pub struct Uses {
150    // 17 bytes + Option byte
151    pub use_method: UseMethod, //1
152    pub remaining: u64,        //8
153    pub total: u64,            //8
154}
155
156#[repr(C)]
157#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
158pub enum TokenStandard {
159    NonFungible,        // This is a master edition
160    FungibleAsset,      // A token with metadata that can also have attrributes
161    Fungible,           // A token with simple metadata
162    NonFungibleEdition, // This is a limited edition
163}
164
165#[repr(C)]
166#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, ShankAccount)]
167pub struct UseAuthorityRecord {
168    pub key: Key,          //1
169    pub allowed_uses: u64, //8
170    pub bump: u8,
171}
172
173impl UseAuthorityRecord {
174    pub fn from_account_info(a: &AccountInfo) -> Result<UseAuthorityRecord, ProgramError> {
175        let ua: UseAuthorityRecord = try_from_slice_checked(
176            &a.data.borrow_mut(),
177            Key::UseAuthorityRecord,
178            USE_AUTHORITY_RECORD_SIZE,
179        )?;
180        Ok(ua)
181    }
182
183    pub fn from_bytes(b: &[u8]) -> Result<UseAuthorityRecord, ProgramError> {
184        let ua: UseAuthorityRecord =
185            try_from_slice_checked(b, Key::UseAuthorityRecord, USE_AUTHORITY_RECORD_SIZE)?;
186        Ok(ua)
187    }
188
189    pub fn bump_empty(&self) -> bool {
190        self.bump == 0 && self.key == Key::UseAuthorityRecord
191    }
192}
193
194#[repr(C)]
195#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, ShankAccount)]
196pub struct CollectionAuthorityRecord {
197    pub key: Key, //1
198    pub bump: u8, //1
199}
200
201impl CollectionAuthorityRecord {
202    pub fn from_account_info(a: &AccountInfo) -> Result<CollectionAuthorityRecord, ProgramError> {
203        let ua: CollectionAuthorityRecord = try_from_slice_checked(
204            &a.data.borrow_mut(),
205            Key::CollectionAuthorityRecord,
206            COLLECTION_AUTHORITY_RECORD_SIZE,
207        )?;
208
209        Ok(ua)
210    }
211
212    pub fn from_bytes(b: &[u8]) -> Result<CollectionAuthorityRecord, ProgramError> {
213        let ca: CollectionAuthorityRecord = try_from_slice_checked(
214            b,
215            Key::CollectionAuthorityRecord,
216            COLLECTION_AUTHORITY_RECORD_SIZE,
217        )?;
218        Ok(ca)
219    }
220}
221
222#[repr(C)]
223#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
224pub struct Collection {
225    pub verified: bool,
226    pub key: Pubkey,
227}
228
229#[repr(C)]
230#[derive(Clone, BorshSerialize, Debug, PartialEq, ShankAccount)]
231pub struct Metadata {
232    pub key: Key,
233    pub update_authority: Pubkey,
234    pub mint: Pubkey,
235    pub data: Data,
236    // Immutable, once flipped, all sales of this metadata are considered secondary.
237    pub primary_sale_happened: bool,
238    // Whether or not the data struct is mutable, default is not
239    pub is_mutable: bool,
240    /// nonce for easy calculation of editions, if present
241    pub edition_nonce: Option<u8>,
242    /// Since we cannot easily change Metadata, we add the new DataV2 fields here at the end.
243    pub token_standard: Option<TokenStandard>,
244    /// Collection
245    pub collection: Option<Collection>,
246    /// Uses
247    pub uses: Option<Uses>,
248}
249
250impl Metadata {
251    pub fn from_account_info(a: &AccountInfo) -> Result<Metadata, ProgramError> {
252        let md: Metadata = meta_deser(&mut a.data.borrow_mut().as_ref())?;
253
254        Ok(md)
255    }
256}
257
258impl borsh::de::BorshDeserialize for Metadata {
259    fn deserialize(buf: &mut &[u8]) -> ::core::result::Result<Self, borsh::maybestd::io::Error> {
260        let md = meta_deser(buf)?;
261        Ok(md)
262    }
263}
264
265pub trait MasterEdition {
266    fn key(&self) -> Key;
267    fn supply(&self) -> u64;
268    fn set_supply(&mut self, supply: u64);
269    fn max_supply(&self) -> Option<u64>;
270    fn save(&self, account: &AccountInfo) -> ProgramResult;
271}
272
273pub fn get_master_edition(account: &AccountInfo) -> Result<Box<dyn MasterEdition>, ProgramError> {
274    let version = account.data.borrow()[0];
275
276    // For some reason when converting Key to u8 here, it becomes unreachable. Use direct constant instead.
277    let master_edition_result: Result<Box<dyn MasterEdition>, ProgramError> = match version {
278        2 => Ok(Box::new(MasterEditionV1::from_account_info(account)?)),
279        6 => Ok(Box::new(MasterEditionV2::from_account_info(account)?)),
280        _ => Err(MetadataError::DataTypeMismatch.into()),
281    };
282
283    master_edition_result
284}
285
286#[repr(C)]
287#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, ShankAccount)]
288pub struct MasterEditionV2 {
289    pub key: Key,
290
291    pub supply: u64,
292
293    pub max_supply: Option<u64>,
294}
295
296impl MasterEdition for MasterEditionV2 {
297    fn key(&self) -> Key {
298        self.key
299    }
300
301    fn supply(&self) -> u64 {
302        self.supply
303    }
304
305    fn set_supply(&mut self, supply: u64) {
306        self.supply = supply;
307    }
308
309    fn max_supply(&self) -> Option<u64> {
310        self.max_supply
311    }
312
313    fn save(&self, account: &AccountInfo) -> ProgramResult {
314        self.serialize(&mut *account.data.borrow_mut())?;
315        Ok(())
316    }
317}
318
319impl MasterEditionV2 {
320    pub fn from_account_info(a: &AccountInfo) -> Result<MasterEditionV2, ProgramError> {
321        let me: MasterEditionV2 = try_from_slice_checked(
322            &a.data.borrow_mut(),
323            Key::MasterEditionV2,
324            MAX_MASTER_EDITION_LEN,
325        )?;
326
327        Ok(me)
328    }
329}
330
331#[repr(C)]
332#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, ShankAccount)]
333pub struct MasterEditionV1 {
334    pub key: Key,
335
336    pub supply: u64,
337
338    pub max_supply: Option<u64>,
339
340    /// Can be used to mint tokens that give one-time permission to mint a single limited edition.
341    pub printing_mint: Pubkey,
342
343    /// If you don't know how many printing tokens you are going to need, but you do know
344    /// you are going to need some amount in the future, you can use a token from this mint.
345    /// Coming back to token metadata with one of these tokens allows you to mint (one time)
346    /// any number of printing tokens you want. This is used for instance by Auction Manager
347    /// with participation NFTs, where we dont know how many people will bid and need participation
348    /// printing tokens to redeem, so we give it ONE of these tokens to use after the auction is over,
349    /// because when the auction begins we just dont know how many printing tokens we will need,
350    /// but at the end we will. At the end it then burns this token with token-metadata to
351    /// get the printing tokens it needs to give to bidders. Each bidder then redeems a printing token
352    /// to get their limited editions.
353    pub one_time_printing_authorization_mint: Pubkey,
354}
355
356impl MasterEdition for MasterEditionV1 {
357    fn key(&self) -> Key {
358        self.key
359    }
360
361    fn supply(&self) -> u64 {
362        self.supply
363    }
364
365    fn max_supply(&self) -> Option<u64> {
366        self.max_supply
367    }
368
369    fn set_supply(&mut self, supply: u64) {
370        self.supply = supply;
371    }
372
373    fn save(&self, account: &AccountInfo) -> ProgramResult {
374        self.serialize(&mut *account.data.borrow_mut())?;
375        Ok(())
376    }
377}
378
379impl MasterEditionV1 {
380    pub fn from_account_info(a: &AccountInfo) -> Result<MasterEditionV1, ProgramError> {
381        let me: MasterEditionV1 = try_from_slice_checked(
382            &a.data.borrow_mut(),
383            Key::MasterEditionV1,
384            MAX_MASTER_EDITION_LEN,
385        )?;
386
387        Ok(me)
388    }
389}
390
391#[repr(C)]
392#[derive(Clone, Debug, PartialEq, BorshSerialize, BorshDeserialize, ShankAccount)]
393/// All Editions should never have a supply greater than 1.
394/// To enforce this, a transfer mint authority instruction will happen when
395/// a normal token is turned into an Edition, and in order for a Metadata update authority
396/// to do this transaction they will also need to sign the transaction as the Mint authority.
397pub struct Edition {
398    pub key: Key,
399
400    /// Points at MasterEdition struct
401    pub parent: Pubkey,
402
403    /// Starting at 0 for master record, this is incremented for each edition minted.
404    pub edition: u64,
405}
406
407impl Edition {
408    pub fn from_account_info(a: &AccountInfo) -> Result<Edition, ProgramError> {
409        let ed: Edition =
410            try_from_slice_checked(&a.data.borrow_mut(), Key::EditionV1, MAX_EDITION_LEN)?;
411
412        Ok(ed)
413    }
414}
415
416#[repr(C)]
417#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
418pub struct Creator {
419    pub address: Pubkey,
420    pub verified: bool,
421    // In percentages, NOT basis points ;) Watch out!
422    pub share: u8,
423}
424
425pub trait ReservationList {
426    fn master_edition(&self) -> Pubkey;
427    fn supply_snapshot(&self) -> Option<u64>;
428    fn reservations(&self) -> Vec<Reservation>;
429    fn total_reservation_spots(&self) -> u64;
430    fn current_reservation_spots(&self) -> u64;
431    fn set_master_edition(&mut self, key: Pubkey);
432    fn set_supply_snapshot(&mut self, supply: Option<u64>);
433    fn set_reservations(&mut self, reservations: Vec<Reservation>) -> ProgramResult;
434    fn add_reservation(
435        &mut self,
436        reservation: Reservation,
437        offset: u64,
438        total_spot_offset: u64,
439    ) -> ProgramResult;
440    fn set_total_reservation_spots(&mut self, total_reservation_spots: u64);
441    fn set_current_reservation_spots(&mut self, current_reservation_spots: u64);
442    fn save(&self, account: &AccountInfo) -> ProgramResult;
443}
444
445pub fn get_reservation_list(
446    account: &AccountInfo,
447) -> Result<Box<dyn ReservationList>, ProgramError> {
448    let version = account.data.borrow()[0];
449
450    // For some reason when converting Key to u8 here, it becomes unreachable. Use direct constant instead.
451    let reservation_list_result: Result<Box<dyn ReservationList>, ProgramError> = match version {
452        3 => Ok(Box::new(ReservationListV1::from_account_info(account)?)),
453        5 => Ok(Box::new(ReservationListV2::from_account_info(account)?)),
454        _ => Err(MetadataError::DataTypeMismatch.into()),
455    };
456
457    reservation_list_result
458}
459
460#[repr(C)]
461#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, ShankAccount)]
462pub struct ReservationListV2 {
463    pub key: Key,
464    /// Present for reverse lookups
465    pub master_edition: Pubkey,
466
467    /// What supply counter was on master_edition when this reservation was created.
468    pub supply_snapshot: Option<u64>,
469    pub reservations: Vec<Reservation>,
470    /// How many reservations there are going to be, given on first set_reservation call
471    pub total_reservation_spots: u64,
472    /// Cached count of reservation spots in the reservation vec to save on CPU.
473    pub current_reservation_spots: u64,
474}
475
476impl ReservationList for ReservationListV2 {
477    fn master_edition(&self) -> Pubkey {
478        self.master_edition
479    }
480
481    fn supply_snapshot(&self) -> Option<u64> {
482        self.supply_snapshot
483    }
484
485    fn reservations(&self) -> Vec<Reservation> {
486        self.reservations.clone()
487    }
488
489    fn set_master_edition(&mut self, key: Pubkey) {
490        self.master_edition = key
491    }
492
493    fn set_supply_snapshot(&mut self, supply: Option<u64>) {
494        self.supply_snapshot = supply;
495    }
496
497    fn add_reservation(
498        &mut self,
499        reservation: Reservation,
500        offset: u64,
501        total_spot_offset: u64,
502    ) -> ProgramResult {
503        let usize_offset = offset as usize;
504        while self.reservations.len() < usize_offset {
505            self.reservations.push(Reservation {
506                address: solana_program::system_program::id(),
507                spots_remaining: 0,
508                total_spots: 0,
509            })
510        }
511        if self.reservations.len() > usize_offset {
512            let replaced_addr = self.reservations[usize_offset].address;
513            let replaced_spots = self.reservations[usize_offset].total_spots;
514
515            if replaced_addr == reservation.address {
516                // Since we will have incremented, decrease in advance so we dont blow the spot check.
517                // Super hacky but this code is to be deprecated.
518                self.set_current_reservation_spots(
519                    self.current_reservation_spots()
520                        .checked_sub(replaced_spots)
521                        .ok_or(MetadataError::NumericalOverflowError)?,
522                );
523            } else if replaced_addr != solana_program::system_program::id() {
524                return Err(MetadataError::TriedToReplaceAnExistingReservation.into());
525            }
526            self.reservations[usize_offset] = reservation;
527        } else {
528            self.reservations.push(reservation)
529        }
530
531        if usize_offset != 0
532            && self.reservations[usize_offset - 1].address == solana_program::system_program::id()
533        {
534            // This becomes an anchor then for calculations... put total spot offset in here.
535            self.reservations[usize_offset - 1].spots_remaining = total_spot_offset;
536            self.reservations[usize_offset - 1].total_spots = total_spot_offset;
537        }
538
539        Ok(())
540    }
541
542    fn set_reservations(&mut self, reservations: Vec<Reservation>) -> ProgramResult {
543        self.reservations = reservations;
544        Ok(())
545    }
546
547    fn save(&self, account: &AccountInfo) -> ProgramResult {
548        self.serialize(&mut *account.data.borrow_mut())?;
549        Ok(())
550    }
551
552    fn total_reservation_spots(&self) -> u64 {
553        self.total_reservation_spots
554    }
555
556    fn set_total_reservation_spots(&mut self, total_reservation_spots: u64) {
557        self.total_reservation_spots = total_reservation_spots;
558    }
559
560    fn current_reservation_spots(&self) -> u64 {
561        self.current_reservation_spots
562    }
563
564    fn set_current_reservation_spots(&mut self, current_reservation_spots: u64) {
565        self.current_reservation_spots = current_reservation_spots;
566    }
567}
568
569impl ReservationListV2 {
570    pub fn from_account_info(a: &AccountInfo) -> Result<ReservationListV2, ProgramError> {
571        let res: ReservationListV2 = try_from_slice_checked(
572            &a.data.borrow_mut(),
573            Key::ReservationListV2,
574            MAX_RESERVATION_LIST_SIZE,
575        )?;
576
577        Ok(res)
578    }
579}
580
581#[repr(C)]
582#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
583pub struct Reservation {
584    pub address: Pubkey,
585    pub spots_remaining: u64,
586    pub total_spots: u64,
587}
588
589// Legacy Reservation List with u8s
590#[repr(C)]
591#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, ShankAccount)]
592pub struct ReservationListV1 {
593    pub key: Key,
594    /// Present for reverse lookups
595    pub master_edition: Pubkey,
596
597    /// What supply counter was on master_edition when this reservation was created.
598    pub supply_snapshot: Option<u64>,
599    pub reservations: Vec<ReservationV1>,
600}
601
602impl ReservationList for ReservationListV1 {
603    fn master_edition(&self) -> Pubkey {
604        self.master_edition
605    }
606
607    fn supply_snapshot(&self) -> Option<u64> {
608        self.supply_snapshot
609    }
610
611    fn reservations(&self) -> Vec<Reservation> {
612        self.reservations
613            .iter()
614            .map(|r| Reservation {
615                address: r.address,
616                spots_remaining: r.spots_remaining as u64,
617                total_spots: r.total_spots as u64,
618            })
619            .collect()
620    }
621
622    fn set_master_edition(&mut self, key: Pubkey) {
623        self.master_edition = key
624    }
625
626    fn set_supply_snapshot(&mut self, supply: Option<u64>) {
627        self.supply_snapshot = supply;
628    }
629
630    fn add_reservation(&mut self, reservation: Reservation, _: u64, _: u64) -> ProgramResult {
631        self.reservations = vec![ReservationV1 {
632            address: reservation.address,
633            spots_remaining: reservation.spots_remaining as u8,
634            total_spots: reservation.total_spots as u8,
635        }];
636
637        Ok(())
638    }
639
640    fn set_reservations(&mut self, reservations: Vec<Reservation>) -> ProgramResult {
641        self.reservations = reservations
642            .iter()
643            .map(|r| ReservationV1 {
644                address: r.address,
645                spots_remaining: r.spots_remaining as u8,
646                total_spots: r.total_spots as u8,
647            })
648            .collect();
649        Ok(())
650    }
651
652    fn save(&self, account: &AccountInfo) -> ProgramResult {
653        self.serialize(&mut *account.data.borrow_mut())?;
654        Ok(())
655    }
656
657    fn total_reservation_spots(&self) -> u64 {
658        self.reservations.iter().map(|r| r.total_spots as u64).sum()
659    }
660
661    fn set_total_reservation_spots(&mut self, _: u64) {}
662
663    fn current_reservation_spots(&self) -> u64 {
664        self.reservations.iter().map(|r| r.total_spots as u64).sum()
665    }
666
667    fn set_current_reservation_spots(&mut self, _: u64) {}
668}
669
670impl ReservationListV1 {
671    pub fn from_account_info(a: &AccountInfo) -> Result<ReservationListV1, ProgramError> {
672        let res: ReservationListV1 = try_from_slice_checked(
673            &a.data.borrow_mut(),
674            Key::ReservationListV1,
675            MAX_RESERVATION_LIST_V1_SIZE,
676        )?;
677
678        Ok(res)
679    }
680}
681
682#[repr(C)]
683#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone)]
684pub struct ReservationV1 {
685    pub address: Pubkey,
686    pub spots_remaining: u8,
687    pub total_spots: u8,
688}
689
690#[repr(C)]
691#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug, Clone, ShankAccount)]
692pub struct EditionMarker {
693    pub key: Key,
694    pub ledger: [u8; 31],
695}
696
697impl EditionMarker {
698    pub fn from_account_info(a: &AccountInfo) -> Result<EditionMarker, ProgramError> {
699        let res: EditionMarker = try_from_slice_checked(
700            &a.data.borrow_mut(),
701            Key::EditionMarker,
702            MAX_EDITION_MARKER_SIZE,
703        )?;
704
705        Ok(res)
706    }
707
708    fn get_edition_offset_from_starting_index(edition: u64) -> Result<usize, ProgramError> {
709        Ok(edition
710            .checked_rem(EDITION_MARKER_BIT_SIZE)
711            .ok_or(MetadataError::NumericalOverflowError)? as usize)
712    }
713
714    fn get_index(offset_from_start: usize) -> Result<usize, ProgramError> {
715        let index = offset_from_start
716            .checked_div(8)
717            .ok_or(MetadataError::NumericalOverflowError)?;
718
719        // With only EDITION_MARKER_BIT_SIZE bits, or 31 bytes, we have a max constraint here.
720        if index > 30 {
721            return Err(MetadataError::InvalidEditionIndex.into());
722        }
723
724        Ok(index)
725    }
726
727    fn get_offset_from_right(offset_from_start: usize) -> Result<u32, ProgramError> {
728        // We're saying the left hand side of a u8 is the 0th index so to get a 1 in that 0th index
729        // you need to shift a 1 over 8 spots from the right hand side. To do that you actually
730        // need not 00000001 but 10000000 which you can get by simply multiplying 1 by 2^7, 128 and then ORing
731        // it with the current value.
732        Ok(7 - offset_from_start
733            .checked_rem(8)
734            .ok_or(MetadataError::NumericalOverflowError)? as u32)
735    }
736
737    fn get_index_and_mask(edition: u64) -> Result<(usize, u8), ProgramError> {
738        // How many editions off we are from edition at 0th index
739        let offset_from_start = EditionMarker::get_edition_offset_from_starting_index(edition)?;
740
741        // How many whole u8s we are from the u8 at the 0th index, which basically dividing by 8
742        let index = EditionMarker::get_index(offset_from_start)?;
743
744        // what position in the given u8 bitset are we (remainder math)
745        let my_position_in_index_starting_from_right =
746            EditionMarker::get_offset_from_right(offset_from_start)?;
747
748        Ok((
749            index,
750            u8::pow(2, my_position_in_index_starting_from_right as u32),
751        ))
752    }
753
754    pub fn edition_taken(&self, edition: u64) -> Result<bool, ProgramError> {
755        let (index, mask) = EditionMarker::get_index_and_mask(edition)?;
756
757        // apply mask with bitwise and with a 1 to determine if it is set or not
758        let applied_mask = self.ledger[index] & mask;
759
760        // What remains should not equal 0.
761        Ok(applied_mask != 0)
762    }
763
764    pub fn insert_edition(&mut self, edition: u64) -> ProgramResult {
765        let (index, mask) = EditionMarker::get_index_and_mask(edition)?;
766        // bitwise or a 1 into our position in that position
767        self.ledger[index] |= mask;
768        Ok(())
769    }
770}