1#[cfg(feature = "serde-traits")]
4use serde::{Deserialize, Serialize};
5use {
6 crate::{
7 error::TokenError,
8 extension::{
9 confidential_transfer::{ConfidentialTransferAccount, ConfidentialTransferMint},
10 confidential_transfer_fee::{
11 ConfidentialTransferFeeAmount, ConfidentialTransferFeeConfig,
12 },
13 cpi_guard::CpiGuard,
14 default_account_state::DefaultAccountState,
15 group_member_pointer::GroupMemberPointer,
16 group_pointer::GroupPointer,
17 immutable_owner::ImmutableOwner,
18 interest_bearing_mint::InterestBearingConfig,
19 memo_transfer::MemoTransfer,
20 metadata_pointer::MetadataPointer,
21 mint_close_authority::MintCloseAuthority,
22 non_transferable::{NonTransferable, NonTransferableAccount},
23 permanent_delegate::PermanentDelegate,
24 transfer_fee::{TransferFeeAmount, TransferFeeConfig},
25 transfer_hook::{TransferHook, TransferHookAccount},
26 },
27 pod::{PodAccount, PodMint},
28 state::{Account, Mint, Multisig, PackedSizeOf},
29 },
30 bytemuck::{Pod, Zeroable},
31 miraland_program::{
32 account_info::AccountInfo,
33 program_error::ProgramError,
34 program_pack::{IsInitialized, Pack},
35 },
36 num_enum::{IntoPrimitive, TryFromPrimitive},
37 spl_pod::{
38 bytemuck::{pod_from_bytes, pod_from_bytes_mut, pod_get_packed_len},
39 primitives::PodU16,
40 },
41 spl_token_group_interface::state::{TokenGroup, TokenGroupMember},
42 spl_type_length_value::variable_len_pack::VariableLenPack,
43 std::{
44 cmp::Ordering,
45 convert::{TryFrom, TryInto},
46 mem::size_of,
47 },
48};
49
50pub mod confidential_transfer;
52pub mod confidential_transfer_fee;
54pub mod cpi_guard;
56pub mod default_account_state;
58pub mod group_member_pointer;
60pub mod group_pointer;
62pub mod immutable_owner;
64pub mod interest_bearing_mint;
66pub mod memo_transfer;
68pub mod metadata_pointer;
70pub mod mint_close_authority;
72pub mod non_transferable;
74pub mod permanent_delegate;
76pub mod reallocate;
78pub mod token_group;
80pub mod token_metadata;
82pub mod transfer_fee;
84pub mod transfer_hook;
86
87#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
89#[repr(transparent)]
90pub struct Length(PodU16);
91impl From<Length> for usize {
92 fn from(n: Length) -> Self {
93 Self::from(u16::from(n.0))
94 }
95}
96impl TryFrom<usize> for Length {
97 type Error = ProgramError;
98 fn try_from(n: usize) -> Result<Self, Self::Error> {
99 u16::try_from(n)
100 .map(|v| Self(PodU16::from(v)))
101 .map_err(|_| ProgramError::AccountDataTooSmall)
102 }
103}
104
105fn get_tlv_indices(type_start: usize) -> TlvIndices {
107 let length_start = type_start.saturating_add(size_of::<ExtensionType>());
108 let value_start = length_start.saturating_add(pod_get_packed_len::<Length>());
109 TlvIndices {
110 type_start,
111 length_start,
112 value_start,
113 }
114}
115
116const fn adjust_len_for_multisig(account_len: usize) -> usize {
119 if account_len == Multisig::LEN {
120 account_len.saturating_add(size_of::<ExtensionType>())
121 } else {
122 account_len
123 }
124}
125
126const fn add_type_and_length_to_len(value_len: usize) -> usize {
129 value_len
130 .saturating_add(size_of::<ExtensionType>())
131 .saturating_add(pod_get_packed_len::<Length>())
132}
133
134#[derive(Debug)]
137struct TlvIndices {
138 pub type_start: usize,
139 pub length_start: usize,
140 pub value_start: usize,
141}
142fn get_extension_indices<V: Extension>(
143 tlv_data: &[u8],
144 init: bool,
145) -> Result<TlvIndices, ProgramError> {
146 let mut start_index = 0;
147 let v_account_type = V::TYPE.get_account_type();
148 while start_index < tlv_data.len() {
149 let tlv_indices = get_tlv_indices(start_index);
150 if tlv_data.len() < tlv_indices.value_start {
151 return Err(ProgramError::InvalidAccountData);
152 }
153 let extension_type =
154 ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
155 let account_type = extension_type.get_account_type();
156 if extension_type == V::TYPE {
157 return Ok(tlv_indices);
159 } else if extension_type == ExtensionType::Uninitialized {
162 if init {
163 return Ok(tlv_indices);
164 } else {
165 return Err(TokenError::ExtensionNotFound.into());
166 }
167 } else if v_account_type != account_type {
168 return Err(TokenError::ExtensionTypeMismatch.into());
169 } else {
170 let length = pod_from_bytes::<Length>(
171 &tlv_data[tlv_indices.length_start..tlv_indices.value_start],
172 )?;
173 let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length));
174 start_index = value_end_index;
175 }
176 }
177 Err(ProgramError::InvalidAccountData)
178}
179
180#[derive(Debug, PartialEq)]
183struct TlvDataInfo {
184 extension_types: Vec<ExtensionType>,
186 used_len: usize,
191}
192
193fn get_tlv_data_info(tlv_data: &[u8]) -> Result<TlvDataInfo, ProgramError> {
196 let mut extension_types = vec![];
197 let mut start_index = 0;
198 while start_index < tlv_data.len() {
199 let tlv_indices = get_tlv_indices(start_index);
200 if tlv_data.len() < tlv_indices.length_start {
201 return Ok(TlvDataInfo {
204 extension_types,
205 used_len: tlv_indices.type_start,
206 });
207 }
208 let extension_type =
209 ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
210 if extension_type == ExtensionType::Uninitialized {
211 return Ok(TlvDataInfo {
212 extension_types,
213 used_len: tlv_indices.type_start,
214 });
215 } else {
216 if tlv_data.len() < tlv_indices.value_start {
217 return Err(ProgramError::InvalidAccountData);
219 }
220 extension_types.push(extension_type);
221 let length = pod_from_bytes::<Length>(
222 &tlv_data[tlv_indices.length_start..tlv_indices.value_start],
223 )?;
224
225 let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length));
226 if value_end_index > tlv_data.len() {
227 return Err(ProgramError::InvalidAccountData);
229 }
230 start_index = value_end_index;
231 }
232 }
233 Ok(TlvDataInfo {
234 extension_types,
235 used_len: start_index,
236 })
237}
238
239fn get_first_extension_type(tlv_data: &[u8]) -> Result<Option<ExtensionType>, ProgramError> {
240 if tlv_data.is_empty() {
241 Ok(None)
242 } else {
243 let tlv_indices = get_tlv_indices(0);
244 if tlv_data.len() <= tlv_indices.length_start {
245 return Ok(None);
246 }
247 let extension_type =
248 ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
249 if extension_type == ExtensionType::Uninitialized {
250 Ok(None)
251 } else {
252 Ok(Some(extension_type))
253 }
254 }
255}
256
257fn check_min_len_and_not_multisig(input: &[u8], minimum_len: usize) -> Result<(), ProgramError> {
258 if input.len() == Multisig::LEN || input.len() < minimum_len {
259 Err(ProgramError::InvalidAccountData)
260 } else {
261 Ok(())
262 }
263}
264
265fn check_account_type<S: BaseState>(account_type: AccountType) -> Result<(), ProgramError> {
266 if account_type != S::ACCOUNT_TYPE {
267 Err(ProgramError::InvalidAccountData)
268 } else {
269 Ok(())
270 }
271}
272
273const BASE_ACCOUNT_LENGTH: usize = Account::LEN;
292const BASE_ACCOUNT_AND_TYPE_LENGTH: usize = BASE_ACCOUNT_LENGTH + size_of::<AccountType>();
295
296fn type_and_tlv_indices<S: BaseState>(
297 rest_input: &[u8],
298) -> Result<Option<(usize, usize)>, ProgramError> {
299 if rest_input.is_empty() {
300 Ok(None)
301 } else {
302 let account_type_index = BASE_ACCOUNT_LENGTH.saturating_sub(S::SIZE_OF);
303 let tlv_start_index = account_type_index.saturating_add(size_of::<AccountType>());
305 if rest_input.len() <= tlv_start_index {
306 return Err(ProgramError::InvalidAccountData);
307 }
308 if rest_input[..account_type_index] != vec![0; account_type_index] {
309 Err(ProgramError::InvalidAccountData)
310 } else {
311 Ok(Some((account_type_index, tlv_start_index)))
312 }
313 }
314}
315
316fn is_initialized_account(input: &[u8]) -> Result<bool, ProgramError> {
319 const ACCOUNT_INITIALIZED_INDEX: usize = 108; if input.len() != BASE_ACCOUNT_LENGTH {
322 return Err(ProgramError::InvalidAccountData);
323 }
324 Ok(input[ACCOUNT_INITIALIZED_INDEX] != 0)
325}
326
327fn get_extension_bytes<S: BaseState, V: Extension>(tlv_data: &[u8]) -> Result<&[u8], ProgramError> {
328 if V::TYPE.get_account_type() != S::ACCOUNT_TYPE {
329 return Err(ProgramError::InvalidAccountData);
330 }
331 let TlvIndices {
332 type_start: _,
333 length_start,
334 value_start,
335 } = get_extension_indices::<V>(tlv_data, false)?;
336 let length = pod_from_bytes::<Length>(&tlv_data[length_start..value_start])?;
339 let value_end = value_start.saturating_add(usize::from(*length));
340 if tlv_data.len() < value_end {
341 return Err(ProgramError::InvalidAccountData);
342 }
343 Ok(&tlv_data[value_start..value_end])
344}
345
346fn get_extension_bytes_mut<S: BaseState, V: Extension>(
347 tlv_data: &mut [u8],
348) -> Result<&mut [u8], ProgramError> {
349 if V::TYPE.get_account_type() != S::ACCOUNT_TYPE {
350 return Err(ProgramError::InvalidAccountData);
351 }
352 let TlvIndices {
353 type_start: _,
354 length_start,
355 value_start,
356 } = get_extension_indices::<V>(tlv_data, false)?;
357 let length = pod_from_bytes::<Length>(&tlv_data[length_start..value_start])?;
360 let value_end = value_start.saturating_add(usize::from(*length));
361 if tlv_data.len() < value_end {
362 return Err(ProgramError::InvalidAccountData);
363 }
364 Ok(&mut tlv_data[value_start..value_end])
365}
366
367fn try_get_new_account_len_for_extension_len<S: BaseState, V: Extension>(
373 tlv_data: &[u8],
374 new_extension_len: usize,
375) -> Result<usize, ProgramError> {
376 let new_extension_tlv_len = add_type_and_length_to_len(new_extension_len);
378 let tlv_info = get_tlv_data_info(tlv_data)?;
379 let current_len = tlv_info
382 .used_len
383 .saturating_add(BASE_ACCOUNT_AND_TYPE_LENGTH);
384 let current_extension_len = get_extension_bytes::<S, V>(tlv_data)
386 .map(|x| add_type_and_length_to_len(x.len()))
387 .unwrap_or(0);
388 let new_len = current_len
389 .saturating_sub(current_extension_len)
390 .saturating_add(new_extension_tlv_len);
391 Ok(adjust_len_for_multisig(new_len))
392}
393
394pub trait BaseStateWithExtensions<S: BaseState> {
396 fn get_tlv_data(&self) -> &[u8];
398
399 fn get_extension_bytes<V: Extension>(&self) -> Result<&[u8], ProgramError> {
401 get_extension_bytes::<S, V>(self.get_tlv_data())
402 }
403
404 fn get_extension<V: Extension + Pod>(&self) -> Result<&V, ProgramError> {
406 pod_from_bytes::<V>(self.get_extension_bytes::<V>()?)
407 }
408
409 fn get_variable_len_extension<V: Extension + VariableLenPack>(
411 &self,
412 ) -> Result<V, ProgramError> {
413 let data = get_extension_bytes::<S, V>(self.get_tlv_data())?;
414 V::unpack_from_slice(data)
415 }
416
417 fn get_extension_types(&self) -> Result<Vec<ExtensionType>, ProgramError> {
419 get_tlv_data_info(self.get_tlv_data()).map(|x| x.extension_types)
420 }
421
422 fn get_first_extension_type(&self) -> Result<Option<ExtensionType>, ProgramError> {
424 get_first_extension_type(self.get_tlv_data())
425 }
426
427 fn try_get_account_len(&self) -> Result<usize, ProgramError> {
429 let tlv_info = get_tlv_data_info(self.get_tlv_data())?;
430 if tlv_info.extension_types.is_empty() {
431 Ok(S::SIZE_OF)
432 } else {
433 let total_len = tlv_info
434 .used_len
435 .saturating_add(BASE_ACCOUNT_AND_TYPE_LENGTH);
436 Ok(adjust_len_for_multisig(total_len))
437 }
438 }
439 fn try_get_new_account_len<V: Extension + Pod>(&self) -> Result<usize, ProgramError> {
444 try_get_new_account_len_for_extension_len::<S, V>(
445 self.get_tlv_data(),
446 pod_get_packed_len::<V>(),
447 )
448 }
449
450 fn try_get_new_account_len_for_variable_len_extension<V: Extension + VariableLenPack>(
453 &self,
454 new_extension: &V,
455 ) -> Result<usize, ProgramError> {
456 try_get_new_account_len_for_extension_len::<S, V>(
457 self.get_tlv_data(),
458 new_extension.get_packed_len()?,
459 )
460 }
461}
462
463#[derive(Clone, Debug, PartialEq)]
466pub struct StateWithExtensionsOwned<S: BaseState> {
467 pub base: S,
469 tlv_data: Vec<u8>,
471}
472impl<S: BaseState + Pack> StateWithExtensionsOwned<S> {
473 pub fn unpack(mut input: Vec<u8>) -> Result<Self, ProgramError> {
477 check_min_len_and_not_multisig(&input, S::SIZE_OF)?;
478 let mut rest = input.split_off(S::SIZE_OF);
479 let base = S::unpack(&input)?;
480 if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::<S>(&rest)? {
481 let account_type = AccountType::try_from(rest[account_type_index])
483 .map_err(|_| ProgramError::InvalidAccountData)?;
484 check_account_type::<S>(account_type)?;
485 let tlv_data = rest.split_off(tlv_start_index);
486 Ok(Self { base, tlv_data })
487 } else {
488 Ok(Self {
489 base,
490 tlv_data: vec![],
491 })
492 }
493 }
494}
495
496impl<S: BaseState> BaseStateWithExtensions<S> for StateWithExtensionsOwned<S> {
497 fn get_tlv_data(&self) -> &[u8] {
498 &self.tlv_data
499 }
500}
501
502#[derive(Debug, PartialEq)]
505pub struct StateWithExtensions<'data, S: BaseState + Pack> {
506 pub base: S,
508 tlv_data: &'data [u8],
510}
511impl<'data, S: BaseState + Pack> StateWithExtensions<'data, S> {
512 pub fn unpack(input: &'data [u8]) -> Result<Self, ProgramError> {
516 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
517 let (base_data, rest) = input.split_at(S::SIZE_OF);
518 let base = S::unpack(base_data)?;
519 let tlv_data = unpack_tlv_data::<S>(rest)?;
520 Ok(Self { base, tlv_data })
521 }
522}
523impl<'a, S: BaseState + Pack> BaseStateWithExtensions<S> for StateWithExtensions<'a, S> {
524 fn get_tlv_data(&self) -> &[u8] {
525 self.tlv_data
526 }
527}
528
529#[derive(Debug, PartialEq)]
532pub struct PodStateWithExtensions<'data, S: BaseState + Pod> {
533 pub base: &'data S,
535 tlv_data: &'data [u8],
537}
538impl<'data, S: BaseState + Pod> PodStateWithExtensions<'data, S> {
539 pub fn unpack(input: &'data [u8]) -> Result<Self, ProgramError> {
543 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
544 let (base_data, rest) = input.split_at(S::SIZE_OF);
545 let base = pod_from_bytes::<S>(base_data)?;
546 if !base.is_initialized() {
547 Err(ProgramError::UninitializedAccount)
548 } else {
549 let tlv_data = unpack_tlv_data::<S>(rest)?;
550 Ok(Self { base, tlv_data })
551 }
552 }
553}
554impl<'a, S: BaseState + Pod> BaseStateWithExtensions<S> for PodStateWithExtensions<'a, S> {
555 fn get_tlv_data(&self) -> &[u8] {
556 self.tlv_data
557 }
558}
559
560pub trait BaseStateWithExtensionsMut<S: BaseState>: BaseStateWithExtensions<S> {
562 fn get_tlv_data_mut(&mut self) -> &mut [u8];
564
565 fn get_account_type_mut(&mut self) -> &mut [u8];
567
568 fn get_extension_bytes_mut<V: Extension>(&mut self) -> Result<&mut [u8], ProgramError> {
570 get_extension_bytes_mut::<S, V>(self.get_tlv_data_mut())
571 }
572
573 fn get_extension_mut<V: Extension + Pod>(&mut self) -> Result<&mut V, ProgramError> {
576 pod_from_bytes_mut::<V>(self.get_extension_bytes_mut::<V>()?)
577 }
578
579 fn pack_variable_len_extension<V: Extension + VariableLenPack>(
582 &mut self,
583 extension: &V,
584 ) -> Result<(), ProgramError> {
585 let data = self.get_extension_bytes_mut::<V>()?;
586 extension.pack_into_slice(data)
589 }
590
591 fn init_extension<V: Extension + Pod + Default>(
597 &mut self,
598 overwrite: bool,
599 ) -> Result<&mut V, ProgramError> {
600 let length = pod_get_packed_len::<V>();
601 let buffer = self.alloc::<V>(length, overwrite)?;
602 let extension_ref = pod_from_bytes_mut::<V>(buffer)?;
603 *extension_ref = V::default();
604 Ok(extension_ref)
605 }
606
607 fn realloc_variable_len_extension<V: Extension + VariableLenPack>(
613 &mut self,
614 new_extension: &V,
615 ) -> Result<(), ProgramError> {
616 let data = self.realloc::<V>(new_extension.get_packed_len()?)?;
617 new_extension.pack_into_slice(data)
618 }
619
620 fn realloc<V: Extension + VariableLenPack>(
630 &mut self,
631 length: usize,
632 ) -> Result<&mut [u8], ProgramError> {
633 let tlv_data = self.get_tlv_data_mut();
634 let TlvIndices {
635 type_start: _,
636 length_start,
637 value_start,
638 } = get_extension_indices::<V>(tlv_data, false)?;
639 let tlv_len = get_tlv_data_info(tlv_data).map(|x| x.used_len)?;
640 let data_len = tlv_data.len();
641
642 let length_ref = pod_from_bytes_mut::<Length>(&mut tlv_data[length_start..value_start])?;
643 let old_length = usize::from(*length_ref);
644
645 if old_length < length {
647 let new_tlv_len = tlv_len.saturating_add(length.saturating_sub(old_length));
648 if new_tlv_len > data_len {
649 return Err(ProgramError::InvalidAccountData);
650 }
651 }
652
653 *length_ref = Length::try_from(length)?;
656
657 let old_value_end = value_start.saturating_add(old_length);
658 let new_value_end = value_start.saturating_add(length);
659 tlv_data.copy_within(old_value_end..tlv_len, new_value_end);
660 match old_length.cmp(&length) {
661 Ordering::Greater => {
662 let new_tlv_len = tlv_len.saturating_sub(old_length.saturating_sub(length));
664 tlv_data[new_tlv_len..tlv_len].fill(0);
665 }
666 Ordering::Less => {
667 tlv_data[old_value_end..new_value_end].fill(0);
669 }
670 Ordering::Equal => {} }
672
673 Ok(&mut tlv_data[value_start..new_value_end])
674 }
675
676 fn init_variable_len_extension<V: Extension + VariableLenPack>(
682 &mut self,
683 extension: &V,
684 overwrite: bool,
685 ) -> Result<(), ProgramError> {
686 let data = self.alloc::<V>(extension.get_packed_len()?, overwrite)?;
687 extension.pack_into_slice(data)
688 }
689
690 fn alloc<V: Extension>(
692 &mut self,
693 length: usize,
694 overwrite: bool,
695 ) -> Result<&mut [u8], ProgramError> {
696 if V::TYPE.get_account_type() != S::ACCOUNT_TYPE {
697 return Err(ProgramError::InvalidAccountData);
698 }
699 let tlv_data = self.get_tlv_data_mut();
700 let TlvIndices {
701 type_start,
702 length_start,
703 value_start,
704 } = get_extension_indices::<V>(tlv_data, true)?;
705
706 if tlv_data[type_start..].len() < add_type_and_length_to_len(length) {
707 return Err(ProgramError::InvalidAccountData);
708 }
709 let extension_type = ExtensionType::try_from(&tlv_data[type_start..length_start])?;
710
711 if extension_type == ExtensionType::Uninitialized || overwrite {
712 let extension_type_array: [u8; 2] = V::TYPE.into();
714 let extension_type_ref = &mut tlv_data[type_start..length_start];
715 extension_type_ref.copy_from_slice(&extension_type_array);
716 let length_ref =
718 pod_from_bytes_mut::<Length>(&mut tlv_data[length_start..value_start])?;
719
720 if overwrite && extension_type == V::TYPE && usize::from(*length_ref) != length {
723 return Err(TokenError::InvalidLengthForAlloc.into());
724 }
725
726 *length_ref = Length::try_from(length)?;
727
728 let value_end = value_start.saturating_add(length);
729 Ok(&mut tlv_data[value_start..value_end])
730 } else {
731 Err(TokenError::ExtensionAlreadyInitialized.into())
733 }
734 }
735
736 fn init_account_extension_from_type(
743 &mut self,
744 extension_type: ExtensionType,
745 ) -> Result<(), ProgramError> {
746 if extension_type.get_account_type() != AccountType::Account {
747 return Ok(());
748 }
749 match extension_type {
750 ExtensionType::TransferFeeAmount => {
751 self.init_extension::<TransferFeeAmount>(true).map(|_| ())
752 }
753 ExtensionType::ImmutableOwner => {
754 self.init_extension::<ImmutableOwner>(true).map(|_| ())
755 }
756 ExtensionType::NonTransferableAccount => self
757 .init_extension::<NonTransferableAccount>(true)
758 .map(|_| ()),
759 ExtensionType::TransferHookAccount => {
760 self.init_extension::<TransferHookAccount>(true).map(|_| ())
761 }
762 ExtensionType::ConfidentialTransferAccount => Ok(()),
765 #[cfg(test)]
766 ExtensionType::AccountPaddingTest => {
767 self.init_extension::<AccountPaddingTest>(true).map(|_| ())
768 }
769 _ => unreachable!(),
770 }
771 }
772
773 fn init_account_type(&mut self) -> Result<(), ProgramError> {
778 let first_extension_type = self.get_first_extension_type()?;
779 let account_type = self.get_account_type_mut();
780 if !account_type.is_empty() {
781 if let Some(extension_type) = first_extension_type {
782 let account_type = extension_type.get_account_type();
783 if account_type != S::ACCOUNT_TYPE {
784 return Err(TokenError::ExtensionBaseMismatch.into());
785 }
786 }
787 account_type[0] = S::ACCOUNT_TYPE.into();
788 }
789 Ok(())
790 }
791
792 fn check_account_type_matches_extension_type(&self) -> Result<(), ProgramError> {
795 if let Some(extension_type) = self.get_first_extension_type()? {
796 let account_type = extension_type.get_account_type();
797 if account_type != S::ACCOUNT_TYPE {
798 return Err(TokenError::ExtensionBaseMismatch.into());
799 }
800 }
801 Ok(())
802 }
803}
804
805#[derive(Debug, PartialEq)]
808pub struct StateWithExtensionsMut<'data, S: BaseState> {
809 pub base: S,
811 base_data: &'data mut [u8],
813 account_type: &'data mut [u8],
815 tlv_data: &'data mut [u8],
817}
818impl<'data, S: BaseState + Pack> StateWithExtensionsMut<'data, S> {
819 pub fn unpack(input: &'data mut [u8]) -> Result<Self, ProgramError> {
823 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
824 let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
825 let base = S::unpack(base_data)?;
826 let (account_type, tlv_data) = unpack_type_and_tlv_data_mut::<S>(rest)?;
827 Ok(Self {
828 base,
829 base_data,
830 account_type,
831 tlv_data,
832 })
833 }
834
835 pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result<Self, ProgramError> {
840 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
841 let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
842 let base = S::unpack_unchecked(base_data)?;
843 if base.is_initialized() {
844 return Err(TokenError::AlreadyInUse.into());
845 }
846 let (account_type, tlv_data) = unpack_uninitialized_type_and_tlv_data_mut::<S>(rest)?;
847 let state = Self {
848 base,
849 base_data,
850 account_type,
851 tlv_data,
852 };
853 state.check_account_type_matches_extension_type()?;
854 Ok(state)
855 }
856
857 pub fn pack_base(&mut self) {
859 S::pack_into_slice(&self.base, self.base_data);
860 }
861}
862impl<'a, S: BaseState> BaseStateWithExtensions<S> for StateWithExtensionsMut<'a, S> {
863 fn get_tlv_data(&self) -> &[u8] {
864 self.tlv_data
865 }
866}
867impl<'a, S: BaseState> BaseStateWithExtensionsMut<S> for StateWithExtensionsMut<'a, S> {
868 fn get_tlv_data_mut(&mut self) -> &mut [u8] {
869 self.tlv_data
870 }
871 fn get_account_type_mut(&mut self) -> &mut [u8] {
872 self.account_type
873 }
874}
875
876#[derive(Debug, PartialEq)]
879pub struct PodStateWithExtensionsMut<'data, S: BaseState> {
880 pub base: &'data mut S,
882 account_type: &'data mut [u8],
884 tlv_data: &'data mut [u8],
886}
887impl<'data, S: BaseState + Pod> PodStateWithExtensionsMut<'data, S> {
888 pub fn unpack(input: &'data mut [u8]) -> Result<Self, ProgramError> {
892 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
893 let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
894 let base = pod_from_bytes_mut::<S>(base_data)?;
895 if !base.is_initialized() {
896 Err(ProgramError::UninitializedAccount)
897 } else {
898 let (account_type, tlv_data) = unpack_type_and_tlv_data_mut::<S>(rest)?;
899 Ok(Self {
900 base,
901 account_type,
902 tlv_data,
903 })
904 }
905 }
906
907 pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result<Self, ProgramError> {
912 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
913 let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
914 let base = pod_from_bytes_mut::<S>(base_data)?;
915 if base.is_initialized() {
916 return Err(TokenError::AlreadyInUse.into());
917 }
918 let (account_type, tlv_data) = unpack_uninitialized_type_and_tlv_data_mut::<S>(rest)?;
919 let state = Self {
920 base,
921 account_type,
922 tlv_data,
923 };
924 state.check_account_type_matches_extension_type()?;
925 Ok(state)
926 }
927}
928
929impl<'a, S: BaseState> BaseStateWithExtensions<S> for PodStateWithExtensionsMut<'a, S> {
930 fn get_tlv_data(&self) -> &[u8] {
931 self.tlv_data
932 }
933}
934impl<'a, S: BaseState> BaseStateWithExtensionsMut<S> for PodStateWithExtensionsMut<'a, S> {
935 fn get_tlv_data_mut(&mut self) -> &mut [u8] {
936 self.tlv_data
937 }
938 fn get_account_type_mut(&mut self) -> &mut [u8] {
939 self.account_type
940 }
941}
942
943fn unpack_tlv_data<S: BaseState>(rest: &[u8]) -> Result<&[u8], ProgramError> {
944 if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::<S>(rest)? {
945 let account_type = AccountType::try_from(rest[account_type_index])
947 .map_err(|_| ProgramError::InvalidAccountData)?;
948 check_account_type::<S>(account_type)?;
949 Ok(&rest[tlv_start_index..])
950 } else {
951 Ok(&[])
952 }
953}
954
955fn unpack_type_and_tlv_data_with_check_mut<
956 S: BaseState,
957 F: Fn(AccountType) -> Result<(), ProgramError>,
958>(
959 rest: &mut [u8],
960 check_fn: F,
961) -> Result<(&mut [u8], &mut [u8]), ProgramError> {
962 if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::<S>(rest)? {
963 let account_type = AccountType::try_from(rest[account_type_index])
965 .map_err(|_| ProgramError::InvalidAccountData)?;
966 check_fn(account_type)?;
967 let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index);
968 Ok((
969 &mut account_type[account_type_index..tlv_start_index],
970 tlv_data,
971 ))
972 } else {
973 Ok((&mut [], &mut []))
974 }
975}
976
977fn unpack_type_and_tlv_data_mut<S: BaseState>(
978 rest: &mut [u8],
979) -> Result<(&mut [u8], &mut [u8]), ProgramError> {
980 unpack_type_and_tlv_data_with_check_mut::<S, _>(rest, check_account_type::<S>)
981}
982
983fn unpack_uninitialized_type_and_tlv_data_mut<S: BaseState>(
984 rest: &mut [u8],
985) -> Result<(&mut [u8], &mut [u8]), ProgramError> {
986 unpack_type_and_tlv_data_with_check_mut::<S, _>(rest, |account_type| {
987 if account_type != AccountType::Uninitialized {
988 Err(ProgramError::InvalidAccountData)
989 } else {
990 Ok(())
991 }
992 })
993}
994
995pub fn set_account_type<S: BaseState>(input: &mut [u8]) -> Result<(), ProgramError> {
1000 check_min_len_and_not_multisig(input, S::SIZE_OF)?;
1001 let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
1002 if S::ACCOUNT_TYPE == AccountType::Account && !is_initialized_account(base_data)? {
1003 return Err(ProgramError::InvalidAccountData);
1004 }
1005 if let Some((account_type_index, _tlv_start_index)) = type_and_tlv_indices::<S>(rest)? {
1006 let mut account_type = AccountType::try_from(rest[account_type_index])
1007 .map_err(|_| ProgramError::InvalidAccountData)?;
1008 if account_type == AccountType::Uninitialized {
1009 rest[account_type_index] = S::ACCOUNT_TYPE.into();
1010 account_type = S::ACCOUNT_TYPE;
1011 }
1012 check_account_type::<S>(account_type)?;
1013 Ok(())
1014 } else {
1015 Err(ProgramError::InvalidAccountData)
1016 }
1017}
1018
1019#[repr(u8)]
1024#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
1025pub enum AccountType {
1026 Uninitialized,
1028 Mint,
1030 Account,
1032}
1033impl Default for AccountType {
1034 fn default() -> Self {
1035 Self::Uninitialized
1036 }
1037}
1038
1039#[repr(u16)]
1043#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
1044#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
1045#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
1046pub enum ExtensionType {
1047 Uninitialized,
1050 TransferFeeConfig,
1053 TransferFeeAmount,
1055 MintCloseAuthority,
1057 ConfidentialTransferMint,
1059 ConfidentialTransferAccount,
1061 DefaultAccountState,
1063 ImmutableOwner,
1065 MemoTransfer,
1067 NonTransferable,
1069 InterestBearingConfig,
1071 CpiGuard,
1073 PermanentDelegate,
1075 NonTransferableAccount,
1078 TransferHook,
1081 TransferHookAccount,
1084 ConfidentialTransferFeeConfig,
1087 ConfidentialTransferFeeAmount,
1089 MetadataPointer,
1092 TokenMetadata,
1094 GroupPointer,
1097 TokenGroup,
1099 GroupMemberPointer,
1102 TokenGroupMember,
1104 #[cfg(test)]
1106 VariableLenMintTest = u16::MAX - 2,
1107 #[cfg(test)]
1110 AccountPaddingTest,
1111 #[cfg(test)]
1114 MintPaddingTest,
1115}
1116impl TryFrom<&[u8]> for ExtensionType {
1117 type Error = ProgramError;
1118 fn try_from(a: &[u8]) -> Result<Self, Self::Error> {
1119 Self::try_from(u16::from_le_bytes(
1120 a.try_into().map_err(|_| ProgramError::InvalidAccountData)?,
1121 ))
1122 .map_err(|_| ProgramError::InvalidAccountData)
1123 }
1124}
1125impl From<ExtensionType> for [u8; 2] {
1126 fn from(a: ExtensionType) -> Self {
1127 u16::from(a).to_le_bytes()
1128 }
1129}
1130impl ExtensionType {
1131 const fn sized(&self) -> bool {
1136 match self {
1137 ExtensionType::TokenMetadata => false,
1138 #[cfg(test)]
1139 ExtensionType::VariableLenMintTest => false,
1140 _ => true,
1141 }
1142 }
1143
1144 fn try_get_type_len(&self) -> Result<usize, ProgramError> {
1148 if !self.sized() {
1149 return Err(ProgramError::InvalidArgument);
1150 }
1151 Ok(match self {
1152 ExtensionType::Uninitialized => 0,
1153 ExtensionType::TransferFeeConfig => pod_get_packed_len::<TransferFeeConfig>(),
1154 ExtensionType::TransferFeeAmount => pod_get_packed_len::<TransferFeeAmount>(),
1155 ExtensionType::MintCloseAuthority => pod_get_packed_len::<MintCloseAuthority>(),
1156 ExtensionType::ImmutableOwner => pod_get_packed_len::<ImmutableOwner>(),
1157 ExtensionType::ConfidentialTransferMint => {
1158 pod_get_packed_len::<ConfidentialTransferMint>()
1159 }
1160 ExtensionType::ConfidentialTransferAccount => {
1161 pod_get_packed_len::<ConfidentialTransferAccount>()
1162 }
1163 ExtensionType::DefaultAccountState => pod_get_packed_len::<DefaultAccountState>(),
1164 ExtensionType::MemoTransfer => pod_get_packed_len::<MemoTransfer>(),
1165 ExtensionType::NonTransferable => pod_get_packed_len::<NonTransferable>(),
1166 ExtensionType::InterestBearingConfig => pod_get_packed_len::<InterestBearingConfig>(),
1167 ExtensionType::CpiGuard => pod_get_packed_len::<CpiGuard>(),
1168 ExtensionType::PermanentDelegate => pod_get_packed_len::<PermanentDelegate>(),
1169 ExtensionType::NonTransferableAccount => pod_get_packed_len::<NonTransferableAccount>(),
1170 ExtensionType::TransferHook => pod_get_packed_len::<TransferHook>(),
1171 ExtensionType::TransferHookAccount => pod_get_packed_len::<TransferHookAccount>(),
1172 ExtensionType::ConfidentialTransferFeeConfig => {
1173 pod_get_packed_len::<ConfidentialTransferFeeConfig>()
1174 }
1175 ExtensionType::ConfidentialTransferFeeAmount => {
1176 pod_get_packed_len::<ConfidentialTransferFeeAmount>()
1177 }
1178 ExtensionType::MetadataPointer => pod_get_packed_len::<MetadataPointer>(),
1179 ExtensionType::TokenMetadata => unreachable!(),
1180 ExtensionType::GroupPointer => pod_get_packed_len::<GroupPointer>(),
1181 ExtensionType::TokenGroup => pod_get_packed_len::<TokenGroup>(),
1182 ExtensionType::GroupMemberPointer => pod_get_packed_len::<GroupMemberPointer>(),
1183 ExtensionType::TokenGroupMember => pod_get_packed_len::<TokenGroupMember>(),
1184 #[cfg(test)]
1185 ExtensionType::AccountPaddingTest => pod_get_packed_len::<AccountPaddingTest>(),
1186 #[cfg(test)]
1187 ExtensionType::MintPaddingTest => pod_get_packed_len::<MintPaddingTest>(),
1188 #[cfg(test)]
1189 ExtensionType::VariableLenMintTest => unreachable!(),
1190 })
1191 }
1192
1193 fn try_get_tlv_len(&self) -> Result<usize, ProgramError> {
1197 Ok(add_type_and_length_to_len(self.try_get_type_len()?))
1198 }
1199
1200 fn try_get_total_tlv_len(extension_types: &[Self]) -> Result<usize, ProgramError> {
1204 let mut extensions = vec![];
1206 for extension_type in extension_types {
1207 if !extensions.contains(&extension_type) {
1208 extensions.push(extension_type);
1209 }
1210 }
1211 extensions.iter().map(|e| e.try_get_tlv_len()).sum()
1212 }
1213
1214 pub fn try_calculate_account_len<S: BaseState>(
1218 extension_types: &[Self],
1219 ) -> Result<usize, ProgramError> {
1220 if extension_types.is_empty() {
1221 Ok(S::SIZE_OF)
1222 } else {
1223 let extension_size = Self::try_get_total_tlv_len(extension_types)?;
1224 let total_len = extension_size.saturating_add(BASE_ACCOUNT_AND_TYPE_LENGTH);
1225 Ok(adjust_len_for_multisig(total_len))
1226 }
1227 }
1228
1229 pub fn get_account_type(&self) -> AccountType {
1231 match self {
1232 ExtensionType::Uninitialized => AccountType::Uninitialized,
1233 ExtensionType::TransferFeeConfig
1234 | ExtensionType::MintCloseAuthority
1235 | ExtensionType::ConfidentialTransferMint
1236 | ExtensionType::DefaultAccountState
1237 | ExtensionType::NonTransferable
1238 | ExtensionType::InterestBearingConfig
1239 | ExtensionType::PermanentDelegate
1240 | ExtensionType::TransferHook
1241 | ExtensionType::ConfidentialTransferFeeConfig
1242 | ExtensionType::MetadataPointer
1243 | ExtensionType::TokenMetadata
1244 | ExtensionType::GroupPointer
1245 | ExtensionType::TokenGroup
1246 | ExtensionType::GroupMemberPointer
1247 | ExtensionType::TokenGroupMember => AccountType::Mint,
1248 ExtensionType::ImmutableOwner
1249 | ExtensionType::TransferFeeAmount
1250 | ExtensionType::ConfidentialTransferAccount
1251 | ExtensionType::MemoTransfer
1252 | ExtensionType::NonTransferableAccount
1253 | ExtensionType::TransferHookAccount
1254 | ExtensionType::CpiGuard
1255 | ExtensionType::ConfidentialTransferFeeAmount => AccountType::Account,
1256 #[cfg(test)]
1257 ExtensionType::VariableLenMintTest => AccountType::Mint,
1258 #[cfg(test)]
1259 ExtensionType::AccountPaddingTest => AccountType::Account,
1260 #[cfg(test)]
1261 ExtensionType::MintPaddingTest => AccountType::Mint,
1262 }
1263 }
1264
1265 pub fn get_required_init_account_extensions(mint_extension_types: &[Self]) -> Vec<Self> {
1268 let mut account_extension_types = vec![];
1269 for extension_type in mint_extension_types {
1270 match extension_type {
1271 ExtensionType::TransferFeeConfig => {
1272 account_extension_types.push(ExtensionType::TransferFeeAmount);
1273 }
1274 ExtensionType::NonTransferable => {
1275 account_extension_types.push(ExtensionType::NonTransferableAccount);
1276 account_extension_types.push(ExtensionType::ImmutableOwner);
1277 }
1278 ExtensionType::TransferHook => {
1279 account_extension_types.push(ExtensionType::TransferHookAccount);
1280 }
1281 #[cfg(test)]
1282 ExtensionType::MintPaddingTest => {
1283 account_extension_types.push(ExtensionType::AccountPaddingTest);
1284 }
1285 _ => {}
1286 }
1287 }
1288 account_extension_types
1289 }
1290
1291 pub fn check_for_invalid_mint_extension_combinations(
1293 mint_extension_types: &[Self],
1294 ) -> Result<(), TokenError> {
1295 let mut transfer_fee_config = false;
1296 let mut confidential_transfer_mint = false;
1297 let mut confidential_transfer_fee_config = false;
1298
1299 for extension_type in mint_extension_types {
1300 match extension_type {
1301 ExtensionType::TransferFeeConfig => transfer_fee_config = true,
1302 ExtensionType::ConfidentialTransferMint => confidential_transfer_mint = true,
1303 ExtensionType::ConfidentialTransferFeeConfig => {
1304 confidential_transfer_fee_config = true
1305 }
1306 _ => (),
1307 }
1308 }
1309
1310 if confidential_transfer_fee_config && !(transfer_fee_config && confidential_transfer_mint)
1311 {
1312 return Err(TokenError::InvalidExtensionCombination);
1313 }
1314
1315 if transfer_fee_config && confidential_transfer_mint && !confidential_transfer_fee_config {
1316 return Err(TokenError::InvalidExtensionCombination);
1317 }
1318
1319 Ok(())
1320 }
1321}
1322
1323pub trait BaseState: PackedSizeOf + IsInitialized {
1325 const ACCOUNT_TYPE: AccountType;
1327}
1328impl BaseState for Account {
1329 const ACCOUNT_TYPE: AccountType = AccountType::Account;
1330}
1331impl BaseState for Mint {
1332 const ACCOUNT_TYPE: AccountType = AccountType::Mint;
1333}
1334impl BaseState for PodAccount {
1335 const ACCOUNT_TYPE: AccountType = AccountType::Account;
1336}
1337impl BaseState for PodMint {
1338 const ACCOUNT_TYPE: AccountType = AccountType::Mint;
1339}
1340
1341pub trait Extension {
1344 const TYPE: ExtensionType;
1346}
1347
1348#[cfg(test)]
1353#[repr(C)]
1354#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
1355pub struct MintPaddingTest {
1356 pub padding1: [u8; 128],
1358 pub padding2: [u8; 48],
1360 pub padding3: [u8; 9],
1362}
1363#[cfg(test)]
1364impl Extension for MintPaddingTest {
1365 const TYPE: ExtensionType = ExtensionType::MintPaddingTest;
1366}
1367#[cfg(test)]
1368impl Default for MintPaddingTest {
1369 fn default() -> Self {
1370 Self {
1371 padding1: [1; 128],
1372 padding2: [2; 48],
1373 padding3: [3; 9],
1374 }
1375 }
1376}
1377#[cfg(test)]
1379#[repr(C)]
1380#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
1381pub struct AccountPaddingTest(MintPaddingTest);
1382#[cfg(test)]
1383impl Extension for AccountPaddingTest {
1384 const TYPE: ExtensionType = ExtensionType::AccountPaddingTest;
1385}
1386
1387pub(crate) fn alloc_and_serialize<S: BaseState + Pod, V: Default + Extension + Pod>(
1402 account_info: &AccountInfo,
1403 new_extension: &V,
1404 overwrite: bool,
1405) -> Result<(), ProgramError> {
1406 let previous_account_len = account_info.try_data_len()?;
1407 let new_account_len = {
1408 let data = account_info.try_borrow_data()?;
1409 let state = PodStateWithExtensions::<S>::unpack(&data)?;
1410 state.try_get_new_account_len::<V>()?
1411 };
1412
1413 if new_account_len > previous_account_len {
1415 account_info.realloc(new_account_len, false)?;
1416 }
1417 let mut buffer = account_info.try_borrow_mut_data()?;
1418 if previous_account_len <= BASE_ACCOUNT_LENGTH {
1419 set_account_type::<S>(*buffer)?;
1420 }
1421 let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1422
1423 let extension = state.init_extension::<V>(overwrite)?;
1425 *extension = *new_extension;
1426
1427 Ok(())
1428}
1429
1430pub(crate) fn alloc_and_serialize_variable_len_extension<
1439 S: BaseState + Pod,
1440 V: Extension + VariableLenPack,
1441>(
1442 account_info: &AccountInfo,
1443 new_extension: &V,
1444 overwrite: bool,
1445) -> Result<(), ProgramError> {
1446 let previous_account_len = account_info.try_data_len()?;
1447 let (new_account_len, extension_already_exists) = {
1448 let data = account_info.try_borrow_data()?;
1449 let state = PodStateWithExtensions::<S>::unpack(&data)?;
1450 let new_account_len =
1451 state.try_get_new_account_len_for_variable_len_extension(new_extension)?;
1452 let extension_already_exists = state.get_extension_bytes::<V>().is_ok();
1453 (new_account_len, extension_already_exists)
1454 };
1455
1456 if extension_already_exists && !overwrite {
1457 return Err(TokenError::ExtensionAlreadyInitialized.into());
1458 }
1459
1460 if previous_account_len < new_account_len {
1461 account_info.realloc(new_account_len, false)?;
1464 let mut buffer = account_info.try_borrow_mut_data()?;
1465 if extension_already_exists {
1466 let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1467 state.realloc_variable_len_extension(new_extension)?;
1468 } else {
1469 if previous_account_len <= BASE_ACCOUNT_LENGTH {
1470 set_account_type::<S>(*buffer)?;
1471 }
1472 let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1474 state.init_variable_len_extension(new_extension, false)?;
1475 }
1476 } else {
1477 let mut buffer = account_info.try_borrow_mut_data()?;
1479 let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1480 if extension_already_exists {
1481 state.realloc_variable_len_extension(new_extension)?;
1482 } else {
1483 state.init_variable_len_extension(new_extension, false)?;
1485 }
1486
1487 let removed_bytes = previous_account_len
1488 .checked_sub(new_account_len)
1489 .ok_or(ProgramError::AccountDataTooSmall)?;
1490 if removed_bytes > 0 {
1491 drop(buffer);
1493 account_info.realloc(new_account_len, false)?;
1494 }
1495 }
1496 Ok(())
1497}
1498
1499#[cfg(test)]
1500mod test {
1501 use {
1502 super::*,
1503 crate::{
1504 pod::test::{TEST_POD_ACCOUNT, TEST_POD_MINT},
1505 state::test::{TEST_ACCOUNT_SLICE, TEST_MINT_SLICE},
1506 },
1507 bytemuck::Pod,
1508 miraland_program::{
1509 account_info::{Account as GetAccount, IntoAccountInfo},
1510 clock::Epoch,
1511 entrypoint::MAX_PERMITTED_DATA_INCREASE,
1512 pubkey::Pubkey,
1513 },
1514 spl_pod::{
1515 bytemuck::pod_bytes_of, optional_keys::OptionalNonZeroPubkey, primitives::PodU64,
1516 },
1517 transfer_fee::test::test_transfer_fee_config,
1518 };
1519
1520 #[repr(C)]
1522 #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
1523 struct FixedLenMintTest {
1524 data: [u8; 8],
1525 }
1526 impl Extension for FixedLenMintTest {
1527 const TYPE: ExtensionType = ExtensionType::MintPaddingTest;
1528 }
1529
1530 #[derive(Clone, Debug, PartialEq)]
1532 struct VariableLenMintTest {
1533 data: Vec<u8>,
1534 }
1535 impl Extension for VariableLenMintTest {
1536 const TYPE: ExtensionType = ExtensionType::VariableLenMintTest;
1537 }
1538 impl VariableLenPack for VariableLenMintTest {
1539 fn pack_into_slice(&self, dst: &mut [u8]) -> Result<(), ProgramError> {
1540 let data_start = size_of::<u64>();
1541 let end = data_start + self.data.len();
1542 if dst.len() < end {
1543 Err(ProgramError::InvalidAccountData)
1544 } else {
1545 dst[..data_start].copy_from_slice(&self.data.len().to_le_bytes());
1546 dst[data_start..end].copy_from_slice(&self.data);
1547 Ok(())
1548 }
1549 }
1550 fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
1551 let data_start = size_of::<u64>();
1552 let length = u64::from_le_bytes(src[..data_start].try_into().unwrap()) as usize;
1553 if src[data_start..data_start + length].len() != length {
1554 return Err(ProgramError::InvalidAccountData);
1555 }
1556 let data = Vec::from(&src[data_start..data_start + length]);
1557 Ok(Self { data })
1558 }
1559 fn get_packed_len(&self) -> Result<usize, ProgramError> {
1560 Ok(size_of::<u64>().saturating_add(self.data.len()))
1561 }
1562 }
1563
1564 const MINT_WITH_EXTENSION: &[u8] = &[
1565 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1566 1, 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1567 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1569 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1570 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 32, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1575 1, 1, ];
1577
1578 #[test]
1579 fn unpack_opaque_buffer() {
1580 let state = PodStateWithExtensions::<PodMint>::unpack(MINT_WITH_EXTENSION).unwrap();
1581 assert_eq!(state.base, &TEST_POD_MINT);
1582 let extension = state.get_extension::<MintCloseAuthority>().unwrap();
1583 let close_authority =
1584 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1585 assert_eq!(extension.close_authority, close_authority);
1586 assert_eq!(
1587 state.get_extension::<TransferFeeConfig>(),
1588 Err(ProgramError::InvalidAccountData)
1589 );
1590 assert_eq!(
1591 PodStateWithExtensions::<PodAccount>::unpack(MINT_WITH_EXTENSION),
1592 Err(ProgramError::UninitializedAccount)
1593 );
1594
1595 let state = PodStateWithExtensions::<PodMint>::unpack(TEST_MINT_SLICE).unwrap();
1596 assert_eq!(state.base, &TEST_POD_MINT);
1597
1598 let mut test_mint = TEST_MINT_SLICE.to_vec();
1599 let state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut test_mint).unwrap();
1600 assert_eq!(state.base, &TEST_POD_MINT);
1601 }
1602
1603 #[test]
1604 fn fail_unpack_opaque_buffer() {
1605 let mut buffer = vec![0, 3];
1607 assert_eq!(
1608 PodStateWithExtensions::<PodMint>::unpack(&buffer),
1609 Err(ProgramError::InvalidAccountData)
1610 );
1611 assert_eq!(
1612 PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer),
1613 Err(ProgramError::InvalidAccountData)
1614 );
1615 assert_eq!(
1616 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer),
1617 Err(ProgramError::InvalidAccountData)
1618 );
1619
1620 let mut buffer = MINT_WITH_EXTENSION.to_vec();
1622 buffer[BASE_ACCOUNT_LENGTH] = 3;
1623 assert_eq!(
1624 PodStateWithExtensions::<PodMint>::unpack(&buffer),
1625 Err(ProgramError::InvalidAccountData)
1626 );
1627
1628 let mut buffer = MINT_WITH_EXTENSION.to_vec();
1630 buffer[45] = 0;
1631 assert_eq!(
1632 PodStateWithExtensions::<PodMint>::unpack(&buffer),
1633 Err(ProgramError::UninitializedAccount)
1634 );
1635
1636 let mut buffer = MINT_WITH_EXTENSION.to_vec();
1638 buffer[PodMint::SIZE_OF] = 100;
1639 assert_eq!(
1640 PodStateWithExtensions::<PodMint>::unpack(&buffer),
1641 Err(ProgramError::InvalidAccountData)
1642 );
1643
1644 let mut buffer = MINT_WITH_EXTENSION.to_vec();
1646 buffer[BASE_ACCOUNT_LENGTH + 1] = 2;
1647 let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1648 assert_eq!(
1649 state.get_extension::<TransferFeeConfig>(),
1650 Err(ProgramError::Custom(
1651 TokenError::ExtensionTypeMismatch as u32
1652 ))
1653 );
1654
1655 let mut buffer = MINT_WITH_EXTENSION.to_vec();
1657 buffer[BASE_ACCOUNT_LENGTH + 3] = 100;
1658 let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1659 assert_eq!(
1660 state.get_extension::<TransferFeeConfig>(),
1661 Err(ProgramError::InvalidAccountData)
1662 );
1663
1664 let mut buffer = MINT_WITH_EXTENSION.to_vec();
1666 buffer[BASE_ACCOUNT_LENGTH + 3] = 10;
1667 let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1668 assert_eq!(
1669 state.get_extension::<TransferFeeConfig>(),
1670 Err(ProgramError::InvalidAccountData)
1671 );
1672
1673 let buffer = &MINT_WITH_EXTENSION[..MINT_WITH_EXTENSION.len() - 1];
1675 let state = PodStateWithExtensions::<PodMint>::unpack(buffer).unwrap();
1676 assert_eq!(
1677 state.get_extension::<MintCloseAuthority>(),
1678 Err(ProgramError::InvalidAccountData)
1679 );
1680 }
1681
1682 #[test]
1683 fn get_extension_types_with_opaque_buffer() {
1684 assert_eq!(
1686 get_tlv_data_info(&[1, 0, 1, 1]).unwrap_err(),
1687 ProgramError::InvalidAccountData,
1688 );
1689 assert_eq!(
1691 get_tlv_data_info(&[0, 1, 0, 0]).unwrap_err(),
1692 ProgramError::InvalidAccountData,
1693 );
1694 assert_eq!(
1696 get_tlv_data_info(&[1, 0, 0, 0]).unwrap(),
1697 TlvDataInfo {
1698 extension_types: vec![ExtensionType::try_from(1).unwrap()],
1699 used_len: add_type_and_length_to_len(0),
1700 }
1701 );
1702 assert_eq!(
1704 get_tlv_data_info(&[0, 0]).unwrap(),
1705 TlvDataInfo {
1706 extension_types: vec![],
1707 used_len: 0
1708 }
1709 );
1710 }
1711
1712 #[test]
1713 fn mint_with_extension_pack_unpack() {
1714 let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
1715 ExtensionType::MintCloseAuthority,
1716 ExtensionType::TransferFeeConfig,
1717 ])
1718 .unwrap();
1719 let mut buffer = vec![0; mint_size];
1720
1721 assert_eq!(
1723 PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer),
1724 Err(ProgramError::UninitializedAccount),
1725 );
1726
1727 let mut state =
1728 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1729 assert_eq!(
1731 state.init_extension::<TransferFeeAmount>(true),
1732 Err(ProgramError::InvalidAccountData),
1733 );
1734
1735 let close_authority =
1737 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1738 let extension = state.init_extension::<MintCloseAuthority>(true).unwrap();
1739 extension.close_authority = close_authority;
1740 assert_eq!(
1741 &state.get_extension_types().unwrap(),
1742 &[ExtensionType::MintCloseAuthority]
1743 );
1744
1745 assert_eq!(
1747 state.init_extension::<MintCloseAuthority>(false),
1748 Err(ProgramError::Custom(
1749 TokenError::ExtensionAlreadyInitialized as u32
1750 ))
1751 );
1752
1753 assert_eq!(
1755 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer),
1756 Err(ProgramError::Custom(
1757 TokenError::ExtensionBaseMismatch as u32
1758 ))
1759 );
1760
1761 assert_eq!(
1763 PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer.clone()),
1764 Err(ProgramError::UninitializedAccount),
1765 );
1766
1767 let mut state =
1769 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1770 *state.base = TEST_POD_MINT;
1771 state.init_account_type().unwrap();
1772
1773 let mut expect = TEST_MINT_SLICE.to_vec();
1775 expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); expect.push(AccountType::Mint.into());
1777 expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes());
1778 expect
1779 .extend_from_slice(&(pod_get_packed_len::<MintCloseAuthority>() as u16).to_le_bytes());
1780 expect.extend_from_slice(&[1; 32]); expect.extend_from_slice(&[0; size_of::<ExtensionType>()]);
1782 expect.extend_from_slice(&[0; size_of::<Length>()]);
1783 expect.extend_from_slice(&[0; size_of::<TransferFeeConfig>()]);
1784 assert_eq!(expect, buffer);
1785
1786 assert_eq!(
1788 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer.clone()),
1789 Err(TokenError::AlreadyInUse.into()),
1790 );
1791
1792 let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
1794
1795 *state.base = TEST_POD_MINT;
1797 state.base.supply = (u64::from(state.base.supply) + 100).into();
1798
1799 let unpacked_extension = state.get_extension_mut::<MintCloseAuthority>().unwrap();
1801 assert_eq!(*unpacked_extension, MintCloseAuthority { close_authority });
1802
1803 let close_authority = OptionalNonZeroPubkey::try_from(None).unwrap();
1805 unpacked_extension.close_authority = close_authority;
1806
1807 let base = *state.base;
1809 let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1810 assert_eq!(state.base, &base);
1811 let unpacked_extension = state.get_extension::<MintCloseAuthority>().unwrap();
1812 assert_eq!(*unpacked_extension, MintCloseAuthority { close_authority });
1813
1814 let mut expect = vec![];
1816 expect.extend_from_slice(bytemuck::bytes_of(&base));
1817 expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); expect.push(AccountType::Mint.into());
1819 expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes());
1820 expect
1821 .extend_from_slice(&(pod_get_packed_len::<MintCloseAuthority>() as u16).to_le_bytes());
1822 expect.extend_from_slice(&[0; 32]);
1823 expect.extend_from_slice(&[0; size_of::<ExtensionType>()]);
1824 expect.extend_from_slice(&[0; size_of::<Length>()]);
1825 expect.extend_from_slice(&[0; size_of::<TransferFeeConfig>()]);
1826 assert_eq!(expect, buffer);
1827
1828 assert_eq!(
1830 PodStateWithExtensions::<PodAccount>::unpack(&buffer),
1831 Err(ProgramError::UninitializedAccount),
1832 );
1833
1834 let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
1835 let mint_transfer_fee = test_transfer_fee_config();
1837 let new_extension = state.init_extension::<TransferFeeConfig>(true).unwrap();
1838 new_extension.transfer_fee_config_authority =
1839 mint_transfer_fee.transfer_fee_config_authority;
1840 new_extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority;
1841 new_extension.withheld_amount = mint_transfer_fee.withheld_amount;
1842 new_extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee;
1843 new_extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee;
1844
1845 assert_eq!(
1846 &state.get_extension_types().unwrap(),
1847 &[
1848 ExtensionType::MintCloseAuthority,
1849 ExtensionType::TransferFeeConfig
1850 ]
1851 );
1852
1853 let mut expect = vec![];
1855 expect.extend_from_slice(pod_bytes_of(&base));
1856 expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); expect.push(AccountType::Mint.into());
1858 expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes());
1859 expect
1860 .extend_from_slice(&(pod_get_packed_len::<MintCloseAuthority>() as u16).to_le_bytes());
1861 expect.extend_from_slice(&[0; 32]); expect.extend_from_slice(&(ExtensionType::TransferFeeConfig as u16).to_le_bytes());
1863 expect.extend_from_slice(&(pod_get_packed_len::<TransferFeeConfig>() as u16).to_le_bytes());
1864 expect.extend_from_slice(pod_bytes_of(&mint_transfer_fee));
1865 assert_eq!(expect, buffer);
1866
1867 let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
1869 assert_eq!(
1870 state.init_extension::<MintPaddingTest>(true),
1871 Err(ProgramError::InvalidAccountData),
1872 );
1873 }
1874
1875 #[test]
1876 fn mint_extension_any_order() {
1877 let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
1878 ExtensionType::MintCloseAuthority,
1879 ExtensionType::TransferFeeConfig,
1880 ])
1881 .unwrap();
1882 let mut buffer = vec![0; mint_size];
1883
1884 let mut state =
1885 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1886 let close_authority =
1888 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1889 let extension = state.init_extension::<MintCloseAuthority>(true).unwrap();
1890 extension.close_authority = close_authority;
1891
1892 let mint_transfer_fee = test_transfer_fee_config();
1893 let extension = state.init_extension::<TransferFeeConfig>(true).unwrap();
1894 extension.transfer_fee_config_authority = mint_transfer_fee.transfer_fee_config_authority;
1895 extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority;
1896 extension.withheld_amount = mint_transfer_fee.withheld_amount;
1897 extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee;
1898 extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee;
1899
1900 assert_eq!(
1901 &state.get_extension_types().unwrap(),
1902 &[
1903 ExtensionType::MintCloseAuthority,
1904 ExtensionType::TransferFeeConfig
1905 ]
1906 );
1907
1908 let mut state =
1910 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1911 *state.base = TEST_POD_MINT;
1912 state.init_account_type().unwrap();
1913
1914 let mut other_buffer = vec![0; mint_size];
1915 let mut state =
1916 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut other_buffer).unwrap();
1917
1918 *state.base = TEST_POD_MINT;
1920 state.init_account_type().unwrap();
1921
1922 let mint_transfer_fee = test_transfer_fee_config();
1924 let extension = state.init_extension::<TransferFeeConfig>(true).unwrap();
1925 extension.transfer_fee_config_authority = mint_transfer_fee.transfer_fee_config_authority;
1926 extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority;
1927 extension.withheld_amount = mint_transfer_fee.withheld_amount;
1928 extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee;
1929 extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee;
1930
1931 let close_authority =
1932 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1933 let extension = state.init_extension::<MintCloseAuthority>(true).unwrap();
1934 extension.close_authority = close_authority;
1935
1936 assert_eq!(
1937 &state.get_extension_types().unwrap(),
1938 &[
1939 ExtensionType::TransferFeeConfig,
1940 ExtensionType::MintCloseAuthority
1941 ]
1942 );
1943
1944 assert_ne!(buffer, other_buffer);
1946 let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1947 let other_state = PodStateWithExtensions::<PodMint>::unpack(&other_buffer).unwrap();
1948
1949 assert_eq!(
1951 state.get_extension::<TransferFeeConfig>().unwrap(),
1952 other_state.get_extension::<TransferFeeConfig>().unwrap()
1953 );
1954 assert_eq!(
1955 state.get_extension::<MintCloseAuthority>().unwrap(),
1956 other_state.get_extension::<MintCloseAuthority>().unwrap()
1957 );
1958 assert_eq!(state.base, other_state.base);
1959 }
1960
1961 #[test]
1962 fn mint_with_multisig_len() {
1963 let mut buffer = vec![0; Multisig::LEN];
1964 assert_eq!(
1965 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer),
1966 Err(ProgramError::InvalidAccountData),
1967 );
1968 let mint_size =
1969 ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MintPaddingTest])
1970 .unwrap();
1971 assert_eq!(mint_size, Multisig::LEN + size_of::<ExtensionType>());
1972 let mut buffer = vec![0; mint_size];
1973
1974 let mut state =
1976 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1977 *state.base = TEST_POD_MINT;
1978 state.init_account_type().unwrap();
1979
1980 let extension = state.init_extension::<MintPaddingTest>(true).unwrap();
1982 extension.padding1 = [1; 128];
1983 extension.padding2 = [1; 48];
1984 extension.padding3 = [1; 9];
1985
1986 assert_eq!(
1987 &state.get_extension_types().unwrap(),
1988 &[ExtensionType::MintPaddingTest]
1989 );
1990
1991 let mut expect = TEST_MINT_SLICE.to_vec();
1993 expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); expect.push(AccountType::Mint.into());
1995 expect.extend_from_slice(&(ExtensionType::MintPaddingTest as u16).to_le_bytes());
1996 expect.extend_from_slice(&(pod_get_packed_len::<MintPaddingTest>() as u16).to_le_bytes());
1997 expect.extend_from_slice(&vec![1; pod_get_packed_len::<MintPaddingTest>()]);
1998 expect.extend_from_slice(&(ExtensionType::Uninitialized as u16).to_le_bytes());
1999 assert_eq!(expect, buffer);
2000 }
2001
2002 #[test]
2003 fn account_with_extension_pack_unpack() {
2004 let account_size = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2005 ExtensionType::TransferFeeAmount,
2006 ])
2007 .unwrap();
2008 let mut buffer = vec![0; account_size];
2009
2010 assert_eq!(
2012 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer),
2013 Err(ProgramError::UninitializedAccount),
2014 );
2015
2016 let mut state =
2017 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2018 assert_eq!(
2020 state.init_extension::<TransferFeeConfig>(true),
2021 Err(ProgramError::InvalidAccountData),
2022 );
2023 let withheld_amount = PodU64::from(u64::MAX);
2025 let extension = state.init_extension::<TransferFeeAmount>(true).unwrap();
2026 extension.withheld_amount = withheld_amount;
2027
2028 assert_eq!(
2029 &state.get_extension_types().unwrap(),
2030 &[ExtensionType::TransferFeeAmount]
2031 );
2032
2033 assert_eq!(
2035 PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer.clone()),
2036 Err(ProgramError::UninitializedAccount),
2037 );
2038
2039 let mut state =
2041 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2042 *state.base = TEST_POD_ACCOUNT;
2043 state.init_account_type().unwrap();
2044 let base = *state.base;
2045
2046 let mut expect = TEST_ACCOUNT_SLICE.to_vec();
2048 expect.push(AccountType::Account.into());
2049 expect.extend_from_slice(&(ExtensionType::TransferFeeAmount as u16).to_le_bytes());
2050 expect.extend_from_slice(&(pod_get_packed_len::<TransferFeeAmount>() as u16).to_le_bytes());
2051 expect.extend_from_slice(&u64::from(withheld_amount).to_le_bytes());
2052 assert_eq!(expect, buffer);
2053
2054 let mut state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2056 assert_eq!(state.base, &base);
2057 assert_eq!(
2058 &state.get_extension_types().unwrap(),
2059 &[ExtensionType::TransferFeeAmount]
2060 );
2061
2062 *state.base = TEST_POD_ACCOUNT;
2064 state.base.amount = (u64::from(state.base.amount) + 100).into();
2065
2066 let unpacked_extension = state.get_extension_mut::<TransferFeeAmount>().unwrap();
2068 assert_eq!(*unpacked_extension, TransferFeeAmount { withheld_amount });
2069
2070 let withheld_amount = PodU64::from(u32::MAX as u64);
2072 unpacked_extension.withheld_amount = withheld_amount;
2073
2074 let base = *state.base;
2076 let state = PodStateWithExtensions::<PodAccount>::unpack(&buffer).unwrap();
2077 assert_eq!(state.base, &base);
2078 let unpacked_extension = state.get_extension::<TransferFeeAmount>().unwrap();
2079 assert_eq!(*unpacked_extension, TransferFeeAmount { withheld_amount });
2080
2081 let mut expect = vec![];
2083 expect.extend_from_slice(pod_bytes_of(&base));
2084 expect.push(AccountType::Account.into());
2085 expect.extend_from_slice(&(ExtensionType::TransferFeeAmount as u16).to_le_bytes());
2086 expect.extend_from_slice(&(pod_get_packed_len::<TransferFeeAmount>() as u16).to_le_bytes());
2087 expect.extend_from_slice(&u64::from(withheld_amount).to_le_bytes());
2088 assert_eq!(expect, buffer);
2089
2090 assert_eq!(
2092 PodStateWithExtensions::<PodMint>::unpack(&buffer),
2093 Err(ProgramError::InvalidAccountData),
2094 );
2095 }
2096
2097 #[test]
2098 fn account_with_multisig_len() {
2099 let mut buffer = vec![0; Multisig::LEN];
2100 assert_eq!(
2101 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer),
2102 Err(ProgramError::InvalidAccountData),
2103 );
2104 let account_size = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2105 ExtensionType::AccountPaddingTest,
2106 ])
2107 .unwrap();
2108 assert_eq!(account_size, Multisig::LEN + size_of::<ExtensionType>());
2109 let mut buffer = vec![0; account_size];
2110
2111 let mut state =
2113 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2114 *state.base = TEST_POD_ACCOUNT;
2115 state.init_account_type().unwrap();
2116
2117 let extension = state.init_extension::<AccountPaddingTest>(true).unwrap();
2119 extension.0.padding1 = [2; 128];
2120 extension.0.padding2 = [2; 48];
2121 extension.0.padding3 = [2; 9];
2122
2123 assert_eq!(
2124 &state.get_extension_types().unwrap(),
2125 &[ExtensionType::AccountPaddingTest]
2126 );
2127
2128 let mut expect = TEST_ACCOUNT_SLICE.to_vec();
2130 expect.push(AccountType::Account.into());
2131 expect.extend_from_slice(&(ExtensionType::AccountPaddingTest as u16).to_le_bytes());
2132 expect
2133 .extend_from_slice(&(pod_get_packed_len::<AccountPaddingTest>() as u16).to_le_bytes());
2134 expect.extend_from_slice(&vec![2; pod_get_packed_len::<AccountPaddingTest>()]);
2135 expect.extend_from_slice(&(ExtensionType::Uninitialized as u16).to_le_bytes());
2136 assert_eq!(expect, buffer);
2137 }
2138
2139 #[test]
2140 fn test_set_account_type() {
2141 let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2143 let needed_len = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2144 ExtensionType::ImmutableOwner,
2145 ])
2146 .unwrap()
2147 - buffer.len();
2148 buffer.append(&mut vec![0; needed_len]);
2149 let err = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap_err();
2150 assert_eq!(err, ProgramError::InvalidAccountData);
2151 set_account_type::<PodAccount>(&mut buffer).unwrap();
2152 let mut state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2154 assert_eq!(state.base, &TEST_POD_ACCOUNT);
2155 assert_eq!(state.account_type[0], AccountType::Account as u8);
2156 state.init_extension::<ImmutableOwner>(true).unwrap(); let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2160 buffer.append(&mut vec![0; 2]);
2161 let err = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap_err();
2162 assert_eq!(err, ProgramError::InvalidAccountData);
2163 set_account_type::<PodAccount>(&mut buffer).unwrap();
2164 let state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2166 assert_eq!(state.base, &TEST_POD_ACCOUNT);
2167 assert_eq!(state.account_type[0], AccountType::Account as u8);
2168
2169 let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2171 buffer.append(&mut vec![2, 0]);
2172 let _ = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2173 set_account_type::<PodAccount>(&mut buffer).unwrap();
2174 let state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2175 assert_eq!(state.base, &TEST_POD_ACCOUNT);
2176 assert_eq!(state.account_type[0], AccountType::Account as u8);
2177
2178 let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2180 buffer.append(&mut vec![1, 0]);
2181 let err = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap_err();
2182 assert_eq!(err, ProgramError::InvalidAccountData);
2183 let err = set_account_type::<PodAccount>(&mut buffer).unwrap_err();
2184 assert_eq!(err, ProgramError::InvalidAccountData);
2185
2186 let mut buffer = TEST_MINT_SLICE.to_vec();
2188 let needed_len = ExtensionType::try_calculate_account_len::<PodMint>(&[
2189 ExtensionType::MintCloseAuthority,
2190 ])
2191 .unwrap()
2192 - buffer.len();
2193 buffer.append(&mut vec![0; needed_len]);
2194 let err = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap_err();
2195 assert_eq!(err, ProgramError::InvalidAccountData);
2196 set_account_type::<PodMint>(&mut buffer).unwrap();
2197 let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
2199 assert_eq!(state.base, &TEST_POD_MINT);
2200 assert_eq!(state.account_type[0], AccountType::Mint as u8);
2201 state.init_extension::<MintCloseAuthority>(true).unwrap();
2202
2203 let mut buffer = TEST_MINT_SLICE.to_vec();
2205 buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2206 buffer.append(&mut vec![0; 2]);
2207 let err = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap_err();
2208 assert_eq!(err, ProgramError::InvalidAccountData);
2209 set_account_type::<PodMint>(&mut buffer).unwrap();
2210 let state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
2212 assert_eq!(state.base, &TEST_POD_MINT);
2213 assert_eq!(state.account_type[0], AccountType::Mint as u8);
2214
2215 let mut buffer = TEST_MINT_SLICE.to_vec();
2217 buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2218 buffer.append(&mut vec![1, 0]);
2219 set_account_type::<PodMint>(&mut buffer).unwrap();
2220 let state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
2221 assert_eq!(state.base, &TEST_POD_MINT);
2222 assert_eq!(state.account_type[0], AccountType::Mint as u8);
2223
2224 let mut buffer = TEST_MINT_SLICE.to_vec();
2226 buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2227 buffer.append(&mut vec![2, 0]);
2228 let err = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap_err();
2229 assert_eq!(err, ProgramError::InvalidAccountData);
2230 let err = set_account_type::<PodMint>(&mut buffer).unwrap_err();
2231 assert_eq!(err, ProgramError::InvalidAccountData);
2232 }
2233
2234 #[test]
2235 fn test_set_account_type_wrongly() {
2236 let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2238 buffer.append(&mut vec![0; 2]);
2239 let err = set_account_type::<PodMint>(&mut buffer).unwrap_err();
2240 assert_eq!(err, ProgramError::InvalidAccountData);
2241
2242 let mut buffer = TEST_MINT_SLICE.to_vec();
2244 buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2245 buffer.append(&mut vec![0; 2]);
2246 let err = set_account_type::<PodAccount>(&mut buffer).unwrap_err();
2247 assert_eq!(err, ProgramError::InvalidAccountData);
2248 }
2249
2250 #[test]
2251 fn test_get_required_init_account_extensions() {
2252 let mint_extensions = vec![
2254 ExtensionType::MintCloseAuthority,
2255 ExtensionType::Uninitialized,
2256 ];
2257 assert_eq!(
2258 ExtensionType::get_required_init_account_extensions(&mint_extensions),
2259 vec![]
2260 );
2261
2262 let mint_extensions = vec![
2264 ExtensionType::TransferFeeConfig,
2265 ExtensionType::MintCloseAuthority,
2266 ];
2267 assert_eq!(
2268 ExtensionType::get_required_init_account_extensions(&mint_extensions),
2269 vec![ExtensionType::TransferFeeAmount]
2270 );
2271
2272 let mint_extensions = vec![
2274 ExtensionType::TransferFeeConfig,
2275 ExtensionType::MintPaddingTest,
2276 ];
2277 assert_eq!(
2278 ExtensionType::get_required_init_account_extensions(&mint_extensions),
2279 vec![
2280 ExtensionType::TransferFeeAmount,
2281 ExtensionType::AccountPaddingTest
2282 ]
2283 );
2284
2285 let mint_extensions = vec![
2287 ExtensionType::TransferFeeConfig,
2288 ExtensionType::TransferFeeConfig,
2289 ];
2290 assert_eq!(
2291 ExtensionType::get_required_init_account_extensions(&mint_extensions),
2292 vec![
2293 ExtensionType::TransferFeeAmount,
2294 ExtensionType::TransferFeeAmount
2295 ]
2296 );
2297 }
2298
2299 #[test]
2300 fn mint_without_extensions() {
2301 let space = ExtensionType::try_calculate_account_len::<PodMint>(&[]).unwrap();
2302 let mut buffer = vec![0; space];
2303 assert_eq!(
2304 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer),
2305 Err(ProgramError::InvalidAccountData),
2306 );
2307
2308 let mut state =
2310 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2311 *state.base = TEST_POD_MINT;
2312 state.init_account_type().unwrap();
2313
2314 assert_eq!(
2316 state.init_extension::<TransferFeeConfig>(true),
2317 Err(ProgramError::InvalidAccountData),
2318 );
2319
2320 assert_eq!(TEST_MINT_SLICE, buffer);
2321 }
2322
2323 #[test]
2324 fn test_init_nonzero_default() {
2325 let mint_size =
2326 ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MintPaddingTest])
2327 .unwrap();
2328 let mut buffer = vec![0; mint_size];
2329 let mut state =
2330 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2331 *state.base = TEST_POD_MINT;
2332 state.init_account_type().unwrap();
2333 let extension = state.init_extension::<MintPaddingTest>(true).unwrap();
2334 assert_eq!(extension.padding1, [1; 128]);
2335 assert_eq!(extension.padding2, [2; 48]);
2336 assert_eq!(extension.padding3, [3; 9]);
2337 }
2338
2339 #[test]
2340 fn test_init_buffer_too_small() {
2341 let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
2342 ExtensionType::MintCloseAuthority,
2343 ])
2344 .unwrap();
2345 let mut buffer = vec![0; mint_size - 1];
2346 let mut state =
2347 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2348 let err = state
2349 .init_extension::<MintCloseAuthority>(true)
2350 .unwrap_err();
2351 assert_eq!(err, ProgramError::InvalidAccountData);
2352
2353 state.tlv_data[0] = 3;
2354 state.tlv_data[2] = 32;
2355 let err = state.get_extension_mut::<MintCloseAuthority>().unwrap_err();
2356 assert_eq!(err, ProgramError::InvalidAccountData);
2357
2358 let mut buffer = vec![0; PodMint::SIZE_OF + 2];
2359 let err =
2360 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap_err();
2361 assert_eq!(err, ProgramError::InvalidAccountData);
2362
2363 let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 3];
2365 let mut state =
2366 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2367 let err = state.get_extension_mut::<MintCloseAuthority>().unwrap_err();
2368 assert_eq!(err, ProgramError::InvalidAccountData);
2369
2370 assert_eq!(state.get_extension_types().unwrap(), vec![]);
2371
2372 let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 2];
2374 let state =
2375 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2376 assert_eq!(state.get_extension_types().unwrap(), []);
2377 }
2378
2379 #[test]
2380 fn test_extension_with_no_data() {
2381 let account_size = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2382 ExtensionType::ImmutableOwner,
2383 ])
2384 .unwrap();
2385 let mut buffer = vec![0; account_size];
2386 let mut state =
2387 PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2388 *state.base = TEST_POD_ACCOUNT;
2389 state.init_account_type().unwrap();
2390
2391 let err = state.get_extension::<ImmutableOwner>().unwrap_err();
2392 assert_eq!(
2393 err,
2394 ProgramError::Custom(TokenError::ExtensionNotFound as u32)
2395 );
2396
2397 state.init_extension::<ImmutableOwner>(true).unwrap();
2398 assert_eq!(
2399 get_first_extension_type(state.tlv_data).unwrap(),
2400 Some(ExtensionType::ImmutableOwner)
2401 );
2402 assert_eq!(
2403 get_tlv_data_info(state.tlv_data).unwrap(),
2404 TlvDataInfo {
2405 extension_types: vec![ExtensionType::ImmutableOwner],
2406 used_len: add_type_and_length_to_len(0)
2407 }
2408 );
2409 }
2410
2411 #[test]
2412 fn fail_account_len_with_metadata() {
2413 assert_eq!(
2414 ExtensionType::try_calculate_account_len::<PodMint>(&[
2415 ExtensionType::MintCloseAuthority,
2416 ExtensionType::VariableLenMintTest,
2417 ExtensionType::TransferFeeConfig,
2418 ])
2419 .unwrap_err(),
2420 ProgramError::InvalidArgument
2421 );
2422 }
2423
2424 #[test]
2425 fn alloc() {
2426 let variable_len = VariableLenMintTest { data: vec![1] };
2427 let alloc_size = variable_len.get_packed_len().unwrap();
2428 let account_size =
2429 BASE_ACCOUNT_LENGTH + size_of::<AccountType>() + add_type_and_length_to_len(alloc_size);
2430 let mut buffer = vec![0; account_size];
2431 let mut state =
2432 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2433 state
2434 .init_variable_len_extension(&variable_len, false)
2435 .unwrap();
2436
2437 assert_eq!(
2439 state
2440 .init_variable_len_extension(&variable_len, false)
2441 .unwrap_err(),
2442 TokenError::ExtensionAlreadyInitialized.into()
2443 );
2444
2445 state
2447 .init_variable_len_extension(&variable_len, true)
2448 .unwrap();
2449
2450 assert_eq!(
2452 state
2453 .init_variable_len_extension(&VariableLenMintTest { data: vec![] }, true)
2454 .unwrap_err(),
2455 TokenError::InvalidLengthForAlloc.into()
2456 );
2457
2458 assert_eq!(
2460 state
2461 .init_variable_len_extension(&VariableLenMintTest { data: vec![1, 2] }, true)
2462 .unwrap_err(),
2463 ProgramError::InvalidAccountData
2464 );
2465 }
2466
2467 #[test]
2468 fn realloc() {
2469 let small_variable_len = VariableLenMintTest {
2470 data: vec![1, 2, 3],
2471 };
2472 let base_variable_len = VariableLenMintTest {
2473 data: vec![1, 2, 3, 4],
2474 };
2475 let big_variable_len = VariableLenMintTest {
2476 data: vec![1, 2, 3, 4, 5],
2477 };
2478 let too_big_variable_len = VariableLenMintTest {
2479 data: vec![1, 2, 3, 4, 5, 6],
2480 };
2481 let account_size =
2482 ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MetadataPointer])
2483 .unwrap()
2484 + add_type_and_length_to_len(big_variable_len.get_packed_len().unwrap());
2485 let mut buffer = vec![0; account_size];
2486 let mut state =
2487 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2488
2489 state
2491 .init_variable_len_extension(&base_variable_len, false)
2492 .unwrap();
2493 let max_pubkey =
2494 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([255; 32]))).unwrap();
2495 let extension = state.init_extension::<MetadataPointer>(false).unwrap();
2496 extension.authority = max_pubkey;
2497 extension.metadata_address = max_pubkey;
2498
2499 state
2501 .realloc_variable_len_extension(&big_variable_len)
2502 .unwrap();
2503 let extension = state
2504 .get_variable_len_extension::<VariableLenMintTest>()
2505 .unwrap();
2506 assert_eq!(extension, big_variable_len);
2507 let extension = state.get_extension::<MetadataPointer>().unwrap();
2508 assert_eq!(extension.authority, max_pubkey);
2509 assert_eq!(extension.metadata_address, max_pubkey);
2510
2511 state
2513 .realloc_variable_len_extension(&small_variable_len)
2514 .unwrap();
2515 let extension = state
2516 .get_variable_len_extension::<VariableLenMintTest>()
2517 .unwrap();
2518 assert_eq!(extension, small_variable_len);
2519 let extension = state.get_extension::<MetadataPointer>().unwrap();
2520 assert_eq!(extension.authority, max_pubkey);
2521 assert_eq!(extension.metadata_address, max_pubkey);
2522 let diff = big_variable_len.get_packed_len().unwrap()
2523 - small_variable_len.get_packed_len().unwrap();
2524 assert_eq!(&buffer[account_size - diff..account_size], vec![0; diff]);
2525
2526 let mut state =
2528 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2529 assert_eq!(
2531 state
2532 .realloc_variable_len_extension(&too_big_variable_len)
2533 .unwrap_err(),
2534 ProgramError::InvalidAccountData,
2535 );
2536 }
2537
2538 #[test]
2539 fn account_len() {
2540 let small_variable_len = VariableLenMintTest {
2541 data: vec![20, 30, 40],
2542 };
2543 let variable_len = VariableLenMintTest {
2544 data: vec![20, 30, 40, 50],
2545 };
2546 let big_variable_len = VariableLenMintTest {
2547 data: vec![20, 30, 40, 50, 60],
2548 };
2549 let value_len = variable_len.get_packed_len().unwrap();
2550 let account_size =
2551 BASE_ACCOUNT_LENGTH + size_of::<AccountType>() + add_type_and_length_to_len(value_len);
2552 let mut buffer = vec![0; account_size];
2553 let mut state =
2554 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2555
2556 let current_len = state.try_get_account_len().unwrap();
2559 assert_eq!(current_len, PodMint::SIZE_OF);
2560 let new_len = state
2561 .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2562 &variable_len,
2563 )
2564 .unwrap();
2565 assert_eq!(
2566 new_len,
2567 BASE_ACCOUNT_AND_TYPE_LENGTH.saturating_add(add_type_and_length_to_len(value_len))
2568 );
2569
2570 state
2571 .init_variable_len_extension::<VariableLenMintTest>(&variable_len, false)
2572 .unwrap();
2573 let current_len = state.try_get_account_len().unwrap();
2574 assert_eq!(current_len, new_len);
2575
2576 let new_len = state
2578 .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2579 &small_variable_len,
2580 )
2581 .unwrap();
2582 assert_eq!(current_len.checked_sub(new_len).unwrap(), 1);
2583
2584 let new_len = state
2586 .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2587 &big_variable_len,
2588 )
2589 .unwrap();
2590 assert_eq!(new_len.checked_sub(current_len).unwrap(), 1);
2591
2592 let new_len = state
2594 .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2595 &variable_len,
2596 )
2597 .unwrap();
2598 assert_eq!(new_len, current_len);
2599 }
2600
2601 struct MiralandAccountData {
2604 data: Vec<u8>,
2605 lamports: u64,
2606 owner: Pubkey,
2607 }
2608 impl MiralandAccountData {
2609 fn new(account_data: &[u8]) -> Self {
2612 let mut data = vec![];
2613 data.extend_from_slice(&(account_data.len() as u64).to_le_bytes());
2614 data.extend_from_slice(account_data);
2615 data.extend_from_slice(&[0; MAX_PERMITTED_DATA_INCREASE]);
2616 Self {
2617 data,
2618 lamports: 10,
2619 owner: Pubkey::new_unique(),
2620 }
2621 }
2622
2623 fn data(&self) -> &[u8] {
2626 let start = size_of::<u64>();
2627 let len = self.len();
2628 &self.data[start..start + len]
2629 }
2630
2631 fn len(&self) -> usize {
2633 self.data
2634 .get(..size_of::<u64>())
2635 .and_then(|slice| slice.try_into().ok())
2636 .map(u64::from_le_bytes)
2637 .unwrap() as usize
2638 }
2639 }
2640 impl GetAccount for MiralandAccountData {
2641 fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch) {
2642 let start = size_of::<u64>();
2644 let len = self.len();
2645 (
2646 &mut self.lamports,
2647 &mut self.data[start..start + len],
2648 &self.owner,
2649 false,
2650 Epoch::default(),
2651 )
2652 }
2653 }
2654
2655 #[test]
2656 fn alloc_new_fixed_len_tlv_in_account_info_from_base_size() {
2657 let fixed_len = FixedLenMintTest {
2658 data: [1, 2, 3, 4, 5, 6, 7, 8],
2659 };
2660 let value_len = pod_get_packed_len::<FixedLenMintTest>();
2661 let base_account_size = PodMint::SIZE_OF;
2662 let mut buffer = vec![0; base_account_size];
2663 let state =
2664 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2665 *state.base = TEST_POD_MINT;
2666
2667 let mut data = MiralandAccountData::new(&buffer);
2668 let key = Pubkey::new_unique();
2669 let account_info = (&key, &mut data).into_account_info();
2670
2671 alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap();
2672 let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH + add_type_and_length_to_len(value_len);
2673 assert_eq!(data.len(), new_account_len);
2674 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2675 assert_eq!(
2676 state.get_extension::<FixedLenMintTest>().unwrap(),
2677 &fixed_len,
2678 );
2679
2680 let account_info = (&key, &mut data).into_account_info();
2682 alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, true).unwrap();
2683
2684 let account_info = (&key, &mut data).into_account_info();
2686 assert_eq!(
2687 alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap_err(),
2688 TokenError::ExtensionAlreadyInitialized.into()
2689 );
2690 }
2691
2692 #[test]
2693 fn alloc_new_variable_len_tlv_in_account_info_from_base_size() {
2694 let variable_len = VariableLenMintTest { data: vec![20, 99] };
2695 let value_len = variable_len.get_packed_len().unwrap();
2696 let base_account_size = PodMint::SIZE_OF;
2697 let mut buffer = vec![0; base_account_size];
2698 let state =
2699 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2700 *state.base = TEST_POD_MINT;
2701
2702 let mut data = MiralandAccountData::new(&buffer);
2703 let key = Pubkey::new_unique();
2704 let account_info = (&key, &mut data).into_account_info();
2705
2706 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2707 &account_info,
2708 &variable_len,
2709 false,
2710 )
2711 .unwrap();
2712 let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH + add_type_and_length_to_len(value_len);
2713 assert_eq!(data.len(), new_account_len);
2714 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2715 assert_eq!(
2716 state
2717 .get_variable_len_extension::<VariableLenMintTest>()
2718 .unwrap(),
2719 variable_len
2720 );
2721
2722 let account_info = (&key, &mut data).into_account_info();
2724 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2725 &account_info,
2726 &variable_len,
2727 true,
2728 )
2729 .unwrap();
2730
2731 let account_info = (&key, &mut data).into_account_info();
2733 assert_eq!(
2734 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2735 &account_info,
2736 &variable_len,
2737 false,
2738 )
2739 .unwrap_err(),
2740 TokenError::ExtensionAlreadyInitialized.into()
2741 );
2742 }
2743
2744 #[test]
2745 fn alloc_new_fixed_len_tlv_in_account_info_from_extended_size() {
2746 let fixed_len = FixedLenMintTest {
2747 data: [1, 2, 3, 4, 5, 6, 7, 8],
2748 };
2749 let value_len = pod_get_packed_len::<FixedLenMintTest>();
2750 let account_size =
2751 ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::GroupPointer])
2752 .unwrap()
2753 + add_type_and_length_to_len(value_len);
2754 let mut buffer = vec![0; account_size];
2755 let mut state =
2756 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2757 *state.base = TEST_POD_MINT;
2758 state.init_account_type().unwrap();
2759
2760 let test_key =
2761 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([20; 32]))).unwrap();
2762 let extension = state.init_extension::<GroupPointer>(false).unwrap();
2763 extension.authority = test_key;
2764 extension.group_address = test_key;
2765
2766 let mut data = MiralandAccountData::new(&buffer);
2767 let key = Pubkey::new_unique();
2768 let account_info = (&key, &mut data).into_account_info();
2769
2770 alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap();
2771 let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH
2772 + add_type_and_length_to_len(value_len)
2773 + add_type_and_length_to_len(size_of::<GroupPointer>());
2774 assert_eq!(data.len(), new_account_len);
2775 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2776 assert_eq!(
2777 state.get_extension::<FixedLenMintTest>().unwrap(),
2778 &fixed_len,
2779 );
2780 let extension = state.get_extension::<GroupPointer>().unwrap();
2781 assert_eq!(extension.authority, test_key);
2782 assert_eq!(extension.group_address, test_key);
2783
2784 let account_info = (&key, &mut data).into_account_info();
2786 alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, true).unwrap();
2787
2788 let account_info = (&key, &mut data).into_account_info();
2790 assert_eq!(
2791 alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap_err(),
2792 TokenError::ExtensionAlreadyInitialized.into()
2793 );
2794 }
2795
2796 #[test]
2797 fn alloc_new_variable_len_tlv_in_account_info_from_extended_size() {
2798 let variable_len = VariableLenMintTest { data: vec![42, 6] };
2799 let value_len = variable_len.get_packed_len().unwrap();
2800 let account_size =
2801 ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MetadataPointer])
2802 .unwrap()
2803 + add_type_and_length_to_len(value_len);
2804 let mut buffer = vec![0; account_size];
2805 let mut state =
2806 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2807 *state.base = TEST_POD_MINT;
2808 state.init_account_type().unwrap();
2809
2810 let test_key =
2811 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([20; 32]))).unwrap();
2812 let extension = state.init_extension::<MetadataPointer>(false).unwrap();
2813 extension.authority = test_key;
2814 extension.metadata_address = test_key;
2815
2816 let mut data = MiralandAccountData::new(&buffer);
2817 let key = Pubkey::new_unique();
2818 let account_info = (&key, &mut data).into_account_info();
2819
2820 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2821 &account_info,
2822 &variable_len,
2823 false,
2824 )
2825 .unwrap();
2826 let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH
2827 + add_type_and_length_to_len(value_len)
2828 + add_type_and_length_to_len(size_of::<MetadataPointer>());
2829 assert_eq!(data.len(), new_account_len);
2830 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2831 assert_eq!(
2832 state
2833 .get_variable_len_extension::<VariableLenMintTest>()
2834 .unwrap(),
2835 variable_len
2836 );
2837 let extension = state.get_extension::<MetadataPointer>().unwrap();
2838 assert_eq!(extension.authority, test_key);
2839 assert_eq!(extension.metadata_address, test_key);
2840
2841 let account_info = (&key, &mut data).into_account_info();
2843 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2844 &account_info,
2845 &variable_len,
2846 true,
2847 )
2848 .unwrap();
2849
2850 let account_info = (&key, &mut data).into_account_info();
2852 assert_eq!(
2853 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2854 &account_info,
2855 &variable_len,
2856 false,
2857 )
2858 .unwrap_err(),
2859 TokenError::ExtensionAlreadyInitialized.into()
2860 );
2861 }
2862
2863 #[test]
2864 fn realloc_variable_len_tlv_in_account_info() {
2865 let variable_len = VariableLenMintTest {
2866 data: vec![1, 2, 3, 4, 5],
2867 };
2868 let alloc_size = variable_len.get_packed_len().unwrap();
2869 let account_size =
2870 ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MetadataPointer])
2871 .unwrap()
2872 + add_type_and_length_to_len(alloc_size);
2873 let mut buffer = vec![0; account_size];
2874 let mut state =
2875 PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2876 *state.base = TEST_POD_MINT;
2877 state.init_account_type().unwrap();
2878
2879 state
2881 .init_variable_len_extension(&variable_len, false)
2882 .unwrap();
2883 let max_pubkey =
2884 OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([255; 32]))).unwrap();
2885 let extension = state.init_extension::<MetadataPointer>(false).unwrap();
2886 extension.authority = max_pubkey;
2887 extension.metadata_address = max_pubkey;
2888
2889 let mut data = MiralandAccountData::new(&buffer);
2891 let key = Pubkey::new_unique();
2892 let account_info = (&key, &mut data).into_account_info();
2893 let variable_len = VariableLenMintTest { data: vec![1, 2] };
2894 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2895 &account_info,
2896 &variable_len,
2897 true,
2898 )
2899 .unwrap();
2900
2901 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2902 let extension = state.get_extension::<MetadataPointer>().unwrap();
2903 assert_eq!(extension.authority, max_pubkey);
2904 assert_eq!(extension.metadata_address, max_pubkey);
2905 let extension = state
2906 .get_variable_len_extension::<VariableLenMintTest>()
2907 .unwrap();
2908 assert_eq!(extension, variable_len);
2909 assert_eq!(data.len(), state.try_get_account_len().unwrap());
2910
2911 let account_info = (&key, &mut data).into_account_info();
2913 let variable_len = VariableLenMintTest {
2914 data: vec![1, 2, 3, 4, 5, 6, 7],
2915 };
2916 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2917 &account_info,
2918 &variable_len,
2919 true,
2920 )
2921 .unwrap();
2922
2923 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2924 let extension = state.get_extension::<MetadataPointer>().unwrap();
2925 assert_eq!(extension.authority, max_pubkey);
2926 assert_eq!(extension.metadata_address, max_pubkey);
2927 let extension = state
2928 .get_variable_len_extension::<VariableLenMintTest>()
2929 .unwrap();
2930 assert_eq!(extension, variable_len);
2931 assert_eq!(data.len(), state.try_get_account_len().unwrap());
2932
2933 let account_info = (&key, &mut data).into_account_info();
2935 let variable_len = VariableLenMintTest {
2936 data: vec![7, 6, 5, 4, 3, 2, 1],
2937 };
2938 alloc_and_serialize_variable_len_extension::<PodMint, _>(
2939 &account_info,
2940 &variable_len,
2941 true,
2942 )
2943 .unwrap();
2944
2945 let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2946 let extension = state.get_extension::<MetadataPointer>().unwrap();
2947 assert_eq!(extension.authority, max_pubkey);
2948 assert_eq!(extension.metadata_address, max_pubkey);
2949 let extension = state
2950 .get_variable_len_extension::<VariableLenMintTest>()
2951 .unwrap();
2952 assert_eq!(extension, variable_len);
2953 assert_eq!(data.len(), state.try_get_account_len().unwrap());
2954 }
2955}