#![no_std]
#[cfg(feature = "const")]
#[doc(hidden)]
pub mod reexport {
pub use pinocchio::pubkey::Pubkey;
}
use core::mem::MaybeUninit;
#[cfg(feature = "const")]
pub use five8_const::decode_32_const;
use pinocchio::pubkey::{Pubkey, MAX_SEEDS, PDA_MARKER};
#[cfg(target_os = "solana")]
use pinocchio::syscalls::sol_sha256;
#[cfg(feature = "const")]
use sha2_const_stable::Sha256;
pub fn derive_address<const N: usize>(
seeds: &[&[u8]; N],
bump: Option<u8>,
program_id: &Pubkey,
) -> Pubkey {
const {
assert!(N < MAX_SEEDS, "number of seeds must be less than MAX_SEEDS");
}
const UNINIT: MaybeUninit<&[u8]> = MaybeUninit::<&[u8]>::uninit();
let mut data = [UNINIT; MAX_SEEDS + 2];
let mut i = 0;
while i < N {
unsafe {
data.get_unchecked_mut(i).write(seeds.get_unchecked(i));
}
i += 1;
}
let bump_seed = [bump.unwrap_or_default()];
unsafe {
if bump.is_some() {
data.get_unchecked_mut(i).write(&bump_seed);
i += 1;
}
data.get_unchecked_mut(i).write(program_id.as_ref());
data.get_unchecked_mut(i + 1).write(PDA_MARKER.as_ref());
}
#[cfg(target_os = "solana")]
{
let mut pda = MaybeUninit::<[u8; 32]>::uninit();
unsafe {
sol_sha256(
data.as_ptr() as *const u8,
(i + 2) as u64,
pda.as_mut_ptr() as *mut u8,
);
}
unsafe { pda.assume_init() }
}
#[cfg(not(target_os = "solana"))]
unreachable!("deriving a pda is only available on target `solana`");
}
#[cfg(feature = "const")]
pub const fn derive_address_const<const N: usize>(
seeds: &[&[u8]; N],
bump: Option<u8>,
program_id: &Pubkey,
) -> Pubkey {
const {
assert!(N < MAX_SEEDS, "number of seeds must be less than MAX_SEEDS");
}
let mut hasher = Sha256::new();
let mut i = 0;
while i < seeds.len() {
hasher = hasher.update(seeds[i]);
i += 1;
}
if let Some(bump) = bump {
hasher
.update(&[bump])
.update(program_id)
.update(PDA_MARKER)
.finalize()
} else {
hasher.update(program_id).update(PDA_MARKER).finalize()
}
}
#[cfg(feature = "const")]
#[macro_export]
macro_rules! pubkey {
( $id:literal ) => {
$crate::from_str($id)
};
}
#[cfg(feature = "const")]
#[macro_export]
macro_rules! declare_id {
( $id:expr ) => {
#[doc = "The constant program ID."]
pub const ID: $crate::reexport::Pubkey = $crate::from_str($id);
#[doc = "Returns `true` if given pubkey is the program ID."]
#[inline]
pub fn check_id(id: &$crate::reexport::Pubkey) -> bool {
id == &ID
}
#[doc = "Returns the program ID."]
#[inline]
pub const fn id() -> $crate::reexport::Pubkey {
ID
}
};
}
#[cfg(feature = "const")]
#[inline(always)]
pub const fn from_str(value: &str) -> Pubkey {
decode_32_const(value)
}