use {
bytemuck::{Pod, Zeroable},
solana_address::Address,
spl_token_2022_interface::extension::{
Extension as SplExtension, ExtensionType as SplExtensionType,
},
};
pub trait ExtensionType: Pod + SplExtension {}
impl<T> ExtensionType for T where T: Pod + SplExtension {}
pub type OptionalAddress = Address;
#[inline(always)]
pub fn is_some_address(addr: &Address) -> bool {
let ptr = addr.as_ref().as_ptr();
unsafe {
(ptr as *const u64).read_unaligned()
| (ptr.add(8) as *const u64).read_unaligned()
| (ptr.add(16) as *const u64).read_unaligned()
| (ptr.add(24) as *const u64).read_unaligned()
!= 0
}
}
#[inline(always)]
pub fn optional_address(addr: &Address) -> Option<&Address> {
if is_some_address(addr) {
Some(addr)
} else {
None
}
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct TransferFee {
pub epoch: [u8; 8],
pub maximum_fee: [u8; 8],
pub transfer_fee_basis_points: [u8; 2],
}
impl TransferFee {
pub fn epoch(&self) -> u64 {
u64::from_le_bytes(self.epoch)
}
pub fn maximum_fee(&self) -> u64 {
u64::from_le_bytes(self.maximum_fee)
}
pub fn basis_points(&self) -> u16 {
u16::from_le_bytes(self.transfer_fee_basis_points)
}
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct TransferFeeConfig {
pub transfer_fee_config_authority: OptionalAddress,
pub withdraw_withheld_authority: OptionalAddress,
pub withheld_amount: [u8; 8],
pub older_transfer_fee: TransferFee,
pub newer_transfer_fee: TransferFee,
}
impl TransferFeeConfig {
pub fn withheld_amount(&self) -> u64 {
u64::from_le_bytes(self.withheld_amount)
}
}
impl SplExtension for TransferFeeConfig {
const TYPE: SplExtensionType = SplExtensionType::TransferFeeConfig;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct TransferFeeAmount {
pub withheld_amount: [u8; 8],
}
impl TransferFeeAmount {
pub fn withheld_amount(&self) -> u64 {
u64::from_le_bytes(self.withheld_amount)
}
}
impl SplExtension for TransferFeeAmount {
const TYPE: SplExtensionType = SplExtensionType::TransferFeeAmount;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct MintCloseAuthority {
pub close_authority: OptionalAddress,
}
impl SplExtension for MintCloseAuthority {
const TYPE: SplExtensionType = SplExtensionType::MintCloseAuthority;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct DefaultAccountState {
pub state: u8,
}
impl SplExtension for DefaultAccountState {
const TYPE: SplExtensionType = SplExtensionType::DefaultAccountState;
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct NonTransferable;
unsafe impl Pod for NonTransferable {}
unsafe impl Zeroable for NonTransferable {}
impl SplExtension for NonTransferable {
const TYPE: SplExtensionType = SplExtensionType::NonTransferable;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct CpiGuard {
pub lock_cpi: u8,
}
impl CpiGuard {
pub fn is_enabled(&self) -> bool {
self.lock_cpi != 0
}
}
impl SplExtension for CpiGuard {
const TYPE: SplExtensionType = SplExtensionType::CpiGuard;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct PermanentDelegate {
pub delegate: OptionalAddress,
}
impl SplExtension for PermanentDelegate {
const TYPE: SplExtensionType = SplExtensionType::PermanentDelegate;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct TransferHook {
pub authority: OptionalAddress,
pub program_id: OptionalAddress,
}
impl SplExtension for TransferHook {
const TYPE: SplExtensionType = SplExtensionType::TransferHook;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct TransferHookAccount {
pub transferring: u8,
}
impl SplExtension for TransferHookAccount {
const TYPE: SplExtensionType = SplExtensionType::TransferHookAccount;
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct NonTransferableAccount;
unsafe impl Pod for NonTransferableAccount {}
unsafe impl Zeroable for NonTransferableAccount {}
impl SplExtension for NonTransferableAccount {
const TYPE: SplExtensionType = SplExtensionType::NonTransferableAccount;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct MetadataPointer {
pub authority: OptionalAddress,
pub metadata_address: OptionalAddress,
}
impl SplExtension for MetadataPointer {
const TYPE: SplExtensionType = SplExtensionType::MetadataPointer;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct GroupPointer {
pub authority: OptionalAddress,
pub group_address: OptionalAddress,
}
impl SplExtension for GroupPointer {
const TYPE: SplExtensionType = SplExtensionType::GroupPointer;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct GroupMemberPointer {
pub authority: OptionalAddress,
pub member_address: OptionalAddress,
}
impl SplExtension for GroupMemberPointer {
const TYPE: SplExtensionType = SplExtensionType::GroupMemberPointer;
}
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
pub struct PausableConfig {
pub authority: OptionalAddress,
pub paused: u8,
}
impl PausableConfig {
pub fn is_paused(&self) -> bool {
self.paused != 0
}
}
impl SplExtension for PausableConfig {
const TYPE: SplExtensionType = SplExtensionType::Pausable;
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PausableAccount;
unsafe impl Pod for PausableAccount {}
unsafe impl Zeroable for PausableAccount {}
impl SplExtension for PausableAccount {
const TYPE: SplExtensionType = SplExtensionType::PausableAccount;
}