use super::SATRUSH_ID;
use solana_pubkey::Pubkey;
pub fn get_satrush_config_address() -> (Pubkey, u8) {
let seeds = &[b"satrush_config".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_event_authority_address() -> (Pubkey, u8) {
let seeds = &[b"__event_authority".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_board_address() -> (Pubkey, u8) {
let seeds = &[b"board".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_round_address(round_id: u32) -> (Pubkey, u8) {
let seeds = &[b"round".as_ref(), &round_id.to_le_bytes()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_public_deployment_address(authority: Pubkey, round_id: u32) -> (Pubkey, u8) {
let seeds = &[
b"public_deployment".as_ref(),
&authority.to_bytes(),
&round_id.to_le_bytes(),
];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_miner_address(authority: Pubkey) -> (Pubkey, u8) {
let seeds = &[b"miner".as_ref(), &authority.to_bytes()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_sats_vault_address() -> (Pubkey, u8) {
let seeds = &[b"sats_vault".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_token_vault_address() -> (Pubkey, u8) {
let seeds = &[b"token_vault".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_epoch_vault_address() -> (Pubkey, u8) {
let seeds = &[b"epoch_vault".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_epoch_vault_iteration_address(iteration_id: u32) -> (Pubkey, u8) {
let seeds = &[b"epoch_vault_iteration".as_ref(), &iteration_id.to_le_bytes()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_epoch_vault_entry_address(iteration_id: u32, authority: Pubkey) -> (Pubkey, u8) {
let seeds = &[
b"epoch_vault_entry".as_ref(),
&iteration_id.to_le_bytes(),
&authority.to_bytes(),
];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_epoch_vault_page_address(iteration_id: u32, page_index: u16) -> (Pubkey, u8) {
let seeds = &[
b"epoch_vault_page".as_ref(),
&iteration_id.to_le_bytes(),
&page_index.to_le_bytes(),
];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_one_btc_vault_address() -> (Pubkey, u8) {
let seeds = &[b"one_btc_vault".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_one_btc_vault_iteration_address(iteration_id: u32) -> (Pubkey, u8) {
let seeds = &[b"one_btc_vault_iteration".as_ref(), &iteration_id.to_le_bytes()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_treasury_address() -> (Pubkey, u8) {
let seeds = &[b"treasury".as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_public_automation_address(authority: Pubkey) -> (Pubkey, u8) {
let seeds = &[b"public_automation".as_ref(), &authority.to_bytes()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub const AFFILIATE_TAG_MIN_LEN: usize = 3;
pub const AFFILIATE_TAG_MAX_LEN: usize = 16;
pub fn validate_affiliate_tag(tag: &str) -> Result<(), String> {
if tag.len() < AFFILIATE_TAG_MIN_LEN || tag.len() > AFFILIATE_TAG_MAX_LEN {
return Err(format!(
"affiliate tag must be {AFFILIATE_TAG_MIN_LEN}-{AFFILIATE_TAG_MAX_LEN} characters, got {}",
tag.len()
));
}
if let Some(bad) = tag
.chars()
.find(|c| !(c.is_ascii_lowercase() || c.is_ascii_digit() || *c == '_' || *c == '-'))
{
return Err(format!("affiliate tag may only contain a-z, 0-9, '_' or '-'; found {bad:?}"));
}
Ok(())
}
pub fn get_affiliate_address(authority: Pubkey) -> (Pubkey, u8) {
let seeds = &[b"affiliate".as_ref(), authority.as_ref()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
pub fn get_affiliate_tag_address(tag: &str) -> (Pubkey, u8) {
let seeds = &[b"affiliate_tag".as_ref(), tag.as_bytes()];
Pubkey::find_program_address(seeds, &SATRUSH_ID)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validate_affiliate_tag_accepts_the_charset_at_both_bounds() {
validate_affiliate_tag("a_0").unwrap();
validate_affiliate_tag("abcdefgh12345_-z").unwrap();
}
#[test]
fn validate_affiliate_tag_rejects_bad_lengths_and_charsets() {
assert!(validate_affiliate_tag("ab").is_err(), "too short");
assert!(validate_affiliate_tag("abcdefgh12345_-zx").is_err(), "17 bytes");
assert!(validate_affiliate_tag("ABC").is_err(), "uppercase");
assert!(validate_affiliate_tag("a.b").is_err(), "dot");
assert!(validate_affiliate_tag("").is_err(), "empty");
}
#[test]
fn validate_affiliate_tag_rejects_tags_that_would_panic_the_derivation() {
assert!(validate_affiliate_tag(&"a".repeat(40)).is_err());
}
}