use solana_pubkey::Pubkey;
#[derive(Debug, Clone)]
pub enum Seed {
String(String),
Bytes(Vec<u8>),
U64(u64),
Address(Pubkey),
}
impl Seed {
fn to_bytes(&self) -> Vec<u8> {
match self {
Seed::String(string_value) => string_value.as_bytes().to_vec(),
Seed::Bytes(byte_vector) => byte_vector.clone(),
Seed::U64(number) => number.to_le_bytes().to_vec(),
Seed::Address(address) => address.to_bytes().to_vec(),
}
}
}
#[must_use]
pub fn get_pda_and_bump(seeds: &[Seed], program_id: &Pubkey) -> (Pubkey, u8) {
let seed_bytes: Vec<Vec<u8>> = seeds.iter().map(|seed| seed.to_bytes()).collect();
let seed_slices: Vec<&[u8]> = seed_bytes.iter().map(|v| v.as_slice()).collect();
Pubkey::find_program_address(&seed_slices, program_id)
}
#[macro_export]
macro_rules! seeds {
($($seed:expr),* $(,)?) => {
vec![$($seed.into()),*]
};
}
impl From<&str> for Seed {
fn from(value: &str) -> Self {
Seed::String(value.to_string())
}
}
impl From<String> for Seed {
fn from(value: String) -> Self {
Seed::String(value)
}
}
impl From<u64> for Seed {
fn from(value: u64) -> Self {
Seed::U64(value)
}
}
impl From<Pubkey> for Seed {
fn from(value: Pubkey) -> Self {
Seed::Address(value)
}
}
impl From<Vec<u8>> for Seed {
fn from(value: Vec<u8>) -> Self {
Seed::Bytes(value)
}
}
impl From<&[u8]> for Seed {
fn from(value: &[u8]) -> Self {
Seed::Bytes(value.to_vec())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seed_conversions() {
let str_seed: Seed = "test".into();
let string_seed: Seed = "test".to_string().into();
let u64_seed: Seed = 42u64.into();
let pubkey_seed: Seed = Pubkey::new_unique().into();
let bytes_seed: Seed = vec![1, 2, 3].into();
let slice_seed: Seed = [1, 2, 3].as_slice().into();
match str_seed {
Seed::String(s) => assert_eq!(s, "test"),
_ => panic!("Expected string seed"),
}
match string_seed {
Seed::String(s) => assert_eq!(s, "test"),
_ => panic!("Expected string seed"),
}
match u64_seed {
Seed::U64(n) => assert_eq!(n, 42),
_ => panic!("Expected u64 seed"),
}
match pubkey_seed {
Seed::Address(_) => {} _ => panic!("Expected pubkey seed"),
}
match bytes_seed {
Seed::Bytes(b) => assert_eq!(b, vec![1, 2, 3]),
_ => panic!("Expected bytes seed"),
}
match slice_seed {
Seed::Bytes(b) => assert_eq!(b, vec![1, 2, 3]),
_ => panic!("Expected bytes seed"),
}
}
#[test]
fn test_seeds_macro() {
let pubkey = Pubkey::new_unique();
let seeds_macro: Vec<Seed> = seeds!["test", 42u64, pubkey];
let seeds_manual: Vec<Seed> = vec!["test".into(), 42u64.into(), pubkey.into()];
assert_eq!(seeds_macro.len(), seeds_manual.len());
assert_eq!(seeds_macro.len(), 3);
}
}