use crate::Pubkey;
use solana_program_error::ProgramError;
pub use solana_sdk_ids::sysvar::instructions::ID as INSTRUCTIONS_SYSVAR_ID;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TokenProgram {
SplToken,
Token2022,
}
impl TokenProgram {
pub const ALL: [Self; 2] = [Self::SplToken, Self::Token2022];
pub const fn address(self) -> Pubkey {
match self {
Self::SplToken => spl_token_2022_interface::inline_spl_token::ID,
Self::Token2022 => spl_token_2022_interface::ID,
}
}
}
impl TryFrom<&Pubkey> for TokenProgram {
type Error = ProgramError;
fn try_from(address: &Pubkey) -> Result<Self, Self::Error> {
Self::ALL
.into_iter()
.find(|program| program.address() == *address)
.ok_or(ProgramError::IncorrectProgramId)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fixtures::pubkey_from_seed;
const _: () = match TokenProgram::SplToken {
TokenProgram::SplToken | TokenProgram::Token2022 => (),
};
#[test]
fn every_program_resolves_from_its_own_address() {
for program in TokenProgram::ALL {
let address = program.address();
assert_eq!(
TokenProgram::try_from(&address),
Ok(program),
"{program:?} should resolve from {address}",
);
}
}
#[test]
fn unrelated_program_cannot_be_resolved_as_token_program() {
assert_eq!(
TokenProgram::try_from(&pubkey_from_seed("not a token program")),
Err(ProgramError::IncorrectProgramId),
);
}
}