1use std::io::{Error, ErrorKind};
4
5use borsh::BorshDeserialize;
6use solana_program::pubkey::Pubkey;
7
8use crate::{
9 accounts::{
10 CollectionAuthorityRecord, MasterEdition, Metadata, MetadataDelegateRecord, TokenRecord,
11 },
12 errors::MplTokenMetadataError,
13 generated::{
14 types::{CollectionToggle, RuleSetToggle, UsesToggle},
15 {instructions::UpdateV1InstructionArgs, types::CollectionDetailsToggle},
16 },
17 types::{
18 Collection, CollectionDetails, Data, Key, ProgrammableConfig, TokenDelegateRole,
19 TokenStandard, TokenState, UpdateArgs, Uses,
20 },
21};
22
23macro_rules! safe_deserialize {
26 ( ($n:tt, $k:tt), $(($name:tt, $key:tt)),+ ) => {
27 safe_deserialize!(($n, $k));
28 safe_deserialize!($( ($name, $key) ),+);
29 };
30 ( ($name:tt, $key:tt) ) => {
31 impl $name {
32 pub fn safe_deserialize(data: &[u8]) -> Result<Self, borsh::maybestd::io::Error> {
33 if data.is_empty() || data[0] != Key::$key as u8 {
34 return Err(borsh::maybestd::io::Error::new(
35 ErrorKind::Other,
36 "DataTypeMismatch",
37 ));
38 }
39 let mut data = data;
41 let result = Self::deserialize(&mut data)?;
42
43 Ok(result)
44 }
45 }
46 };
47}
48
49safe_deserialize!(
50 (CollectionAuthorityRecord, CollectionAuthorityRecord),
51 (MasterEdition, MasterEditionV2),
52 (MetadataDelegateRecord, MetadataDelegate)
53);
54
55impl Default for UpdateV1InstructionArgs {
58 fn default() -> Self {
59 Self {
60 new_update_authority: None,
61 data: None,
62 primary_sale_happened: None,
63 is_mutable: None,
64 collection: CollectionToggle::None,
65 collection_details: CollectionDetailsToggle::None,
66 uses: UsesToggle::None,
67 rule_set: RuleSetToggle::None,
68 authorization_data: None,
69 }
70 }
71}
72
73impl Copy for TokenStandard {}
76
77impl Metadata {
80 pub fn safe_deserialize(data: &[u8]) -> Result<Self, borsh::maybestd::io::Error> {
81 if data.is_empty() || data[0] != Key::MetadataV1 as u8 {
82 return Err(borsh::maybestd::io::Error::new(
83 ErrorKind::Other,
84 "DataTypeMismatch",
85 ));
86 }
87 let mut data = data;
89 let result = Self::deserialize_unchecked(&mut data)?;
90
91 Ok(result)
92 }
93
94 fn deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, borsh::maybestd::io::Error> {
95 let key: Key = BorshDeserialize::deserialize(buf)?;
97 let update_authority: Pubkey = BorshDeserialize::deserialize(buf)?;
98 let mint: Pubkey = BorshDeserialize::deserialize(buf)?;
99 let data: Data = BorshDeserialize::deserialize(buf)?;
100 let primary_sale_happened: bool = BorshDeserialize::deserialize(buf)?;
101 let is_mutable: bool = BorshDeserialize::deserialize(buf)?;
102 let edition_nonce: Option<u8> = BorshDeserialize::deserialize(buf)?;
103
104 let token_standard_res: Result<Option<TokenStandard>, borsh::maybestd::io::Error> =
106 BorshDeserialize::deserialize(buf);
107 let collection_res: Result<Option<Collection>, borsh::maybestd::io::Error> =
108 BorshDeserialize::deserialize(buf);
109 let uses_res: Result<Option<Uses>, borsh::maybestd::io::Error> =
110 BorshDeserialize::deserialize(buf);
111
112 let collection_details_res: Result<Option<CollectionDetails>, borsh::maybestd::io::Error> =
114 BorshDeserialize::deserialize(buf);
115
116 let programmable_config_res: Result<
118 Option<ProgrammableConfig>,
119 borsh::maybestd::io::Error,
120 > = BorshDeserialize::deserialize(buf);
121
122 let (token_standard, collection, uses) =
126 match (token_standard_res, collection_res, uses_res) {
127 (Ok(token_standard_res), Ok(collection_res), Ok(uses_res)) => {
128 (token_standard_res, collection_res, uses_res)
129 }
130 _ => (None, None, None),
131 };
132
133 let collection_details = match collection_details_res {
135 Ok(details) => details,
136 Err(_) => None,
137 };
138
139 let programmable_config = programmable_config_res.unwrap_or(None);
141
142 let metadata = Metadata {
143 key,
144 update_authority,
145 mint,
146 name: data.name,
147 seller_fee_basis_points: data.seller_fee_basis_points,
148 symbol: data.symbol,
149 uri: data.uri,
150 creators: data.creators,
151 primary_sale_happened,
152 is_mutable,
153 edition_nonce,
154 token_standard,
155 collection,
156 uses,
157 collection_details,
158 programmable_config,
159 };
160
161 Ok(metadata)
162 }
163}
164
165const LOCKED_TRANSFER_SIZE: usize = 33;
168
169impl TokenRecord {
170 pub fn safe_deserialize(data: &[u8]) -> Result<TokenRecord, Error> {
171 let length = TokenRecord::LEN as i64 - data.len() as i64;
174
175 if !(length == 0 || length == LOCKED_TRANSFER_SIZE as i64)
178 || data[0] != Key::TokenRecord as u8
179 {
180 return Err(Error::new(
181 ErrorKind::InvalidData,
182 MplTokenMetadataError::DataTypeMismatch,
183 ));
184 }
185 let mut data = data;
187
188 let key: Key = BorshDeserialize::deserialize(&mut data)?;
189 let bump: u8 = BorshDeserialize::deserialize(&mut data)?;
190 let state: TokenState = BorshDeserialize::deserialize(&mut data)?;
191 let rule_set_revision: Option<u64> = BorshDeserialize::deserialize(&mut data)?;
192 let delegate: Option<Pubkey> = BorshDeserialize::deserialize(&mut data)?;
193 let delegate_role: Option<TokenDelegateRole> = BorshDeserialize::deserialize(&mut data)?;
194
195 let locked_transfer: Option<Pubkey> = if length == 0 {
196 BorshDeserialize::deserialize(&mut data)?
197 } else {
198 None
199 };
200
201 Ok(TokenRecord {
202 key,
203 bump,
204 state,
205 rule_set_revision,
206 delegate,
207 delegate_role,
208 locked_transfer,
209 })
210 }
211}
212
213impl Default for UpdateArgs {
216 fn default() -> Self {
217 Self::V1 {
218 new_update_authority: None,
219 data: None,
220 primary_sale_happened: None,
221 is_mutable: None,
222 collection: CollectionToggle::None,
223 collection_details: CollectionDetailsToggle::None,
224 uses: UsesToggle::None,
225 rule_set: RuleSetToggle::None,
226 authorization_data: None,
227 }
228 }
229}
230
231impl UpdateArgs {
232 pub fn default_as_update_authority() -> Self {
233 Self::AsUpdateAuthorityV2 {
234 new_update_authority: None,
235 data: None,
236 primary_sale_happened: None,
237 is_mutable: None,
238 collection: CollectionToggle::None,
239 collection_details: CollectionDetailsToggle::None,
240 uses: UsesToggle::None,
241 rule_set: RuleSetToggle::None,
242 token_standard: None,
243 authorization_data: None,
244 }
245 }
246
247 pub fn default_as_authority_item_delegate() -> Self {
248 Self::AsAuthorityItemDelegateV2 {
249 new_update_authority: None,
250 primary_sale_happened: None,
251 is_mutable: None,
252 token_standard: None,
253 authorization_data: None,
254 }
255 }
256
257 pub fn default_as_collection_delegate() -> Self {
258 Self::AsCollectionDelegateV2 {
259 collection: CollectionToggle::None,
260 authorization_data: None,
261 }
262 }
263
264 pub fn default_as_data_delegate() -> Self {
265 Self::AsDataDelegateV2 {
266 data: None,
267 authorization_data: None,
268 }
269 }
270
271 pub fn default_as_programmable_config_delegate() -> Self {
272 Self::AsProgrammableConfigDelegateV2 {
273 rule_set: RuleSetToggle::None,
274 authorization_data: None,
275 }
276 }
277
278 pub fn default_as_data_item_delegate() -> Self {
279 Self::AsDataItemDelegateV2 {
280 data: None,
281 authorization_data: None,
282 }
283 }
284
285 pub fn default_as_collection_item_delegate() -> Self {
286 Self::AsCollectionItemDelegateV2 {
287 collection: CollectionToggle::None,
288 authorization_data: None,
289 }
290 }
291
292 pub fn default_as_programmable_config_item_delegate() -> Self {
293 Self::AsProgrammableConfigItemDelegateV2 {
294 rule_set: RuleSetToggle::None,
295 authorization_data: None,
296 }
297 }
298}
299
300impl Copy for Key {}