use sha2::{Digest, Sha256};
use solana_pubkey::Pubkey;
pub const PHOENIX_PROGRAM_ID: Pubkey =
solana_pubkey::pubkey!("EtrnLzgbS7nMMy5fbD42kXiUzGg8XQzJ972Xtk1cjWih");
pub const PHOENIX_LOG_AUTHORITY: Pubkey =
solana_pubkey::pubkey!("GdxfTLSsdSY37G6fZoYtdGDSfgFnbT2EmRpuePZxWShS");
pub const PHOENIX_GLOBAL_CONFIGURATION: Pubkey =
solana_pubkey::pubkey!("2zskx2iyCvb6Stg7RBZkt1f6MrF4dpYtMG3yMvKwqtUZ");
pub const EMBER_PROGRAM_ID: Pubkey =
solana_pubkey::pubkey!("EMBERpYNE6ehWmXymZZS2skiFmCa9V5dp14e1iduM5qy");
pub const USDC_MINT: Pubkey =
solana_pubkey::pubkey!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
pub const SPL_TOKEN_PROGRAM_ID: Pubkey =
solana_pubkey::pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
pub const ASSOCIATED_TOKEN_PROGRAM_ID: Pubkey =
solana_pubkey::pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL");
pub const SYSTEM_PROGRAM_ID: Pubkey = solana_pubkey::pubkey!("11111111111111111111111111111111");
pub fn compute_discriminant(input: &str) -> [u8; 8] {
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
let result = hasher.finalize();
let mut discriminant = [0u8; 8];
discriminant.copy_from_slice(&result[..8]);
discriminant
}
pub fn place_limit_order_discriminant() -> [u8; 8] {
compute_discriminant("global:place_limit_order")
}
pub fn place_market_order_discriminant() -> [u8; 8] {
compute_discriminant("global:place_market_order")
}
pub fn cancel_orders_by_id_discriminant() -> [u8; 8] {
compute_discriminant("global:cancel_orders_by_id")
}
pub fn deposit_funds_discriminant() -> [u8; 8] {
compute_discriminant("global:deposit_funds")
}
pub fn ember_deposit_discriminant() -> [u8; 8] {
compute_discriminant("global:deposit")
}
pub fn withdraw_funds_discriminant() -> [u8; 8] {
compute_discriminant("global:withdraw_funds")
}
pub fn ember_withdraw_discriminant() -> [u8; 8] {
compute_discriminant("global:withdraw")
}
pub fn register_trader_discriminant() -> [u8; 8] {
compute_discriminant("global:register_trader")
}
pub fn transfer_collateral_discriminant() -> [u8; 8] {
compute_discriminant("global:transfer_collateral")
}
pub fn transfer_collateral_child_to_parent_discriminant() -> [u8; 8] {
compute_discriminant("global:transfer_collateral_child_to_parent")
}
pub fn sync_parent_to_child_discriminant() -> [u8; 8] {
compute_discriminant("global:sync_parent_to_child")
}
pub fn place_multi_limit_order_discriminant() -> [u8; 8] {
compute_discriminant("global:place_multi_limit_order")
}
pub fn cancel_stop_loss_discriminant() -> [u8; 8] {
compute_discriminant("global:cancel_stop_loss")
}
pub fn create_conditional_orders_account_discriminant() -> [u8; 8] {
compute_discriminant("global:create_conditional_orders_account")
}
pub fn place_position_conditional_order_discriminant() -> [u8; 8] {
compute_discriminant("global:place_position_conditional_order")
}
pub fn cancel_conditional_order_discriminant() -> [u8; 8] {
compute_discriminant("global:cancel_conditional_order")
}
pub fn place_attached_conditional_order_discriminant() -> [u8; 8] {
compute_discriminant("global:place_attached_conditional_order")
}
pub fn place_limit_order_with_conditionals_discriminant() -> [u8; 8] {
compute_discriminant("global:place_limit_order_with_conditionals")
}
pub fn get_stop_loss_address(trader_account: &Pubkey, asset_id: u64) -> Pubkey {
let (pda, _bump) = Pubkey::find_program_address(
&[
b"stoploss",
trader_account.as_ref(),
&asset_id.to_le_bytes(),
],
&PHOENIX_PROGRAM_ID,
);
pda
}
pub fn get_conditional_orders_address(trader_account: &Pubkey) -> Pubkey {
let (pda, _bump) = Pubkey::find_program_address(
&[b"conditional_orders", trader_account.as_ref()],
&PHOENIX_PROGRAM_ID,
);
pda
}
pub fn get_spline_collection_address(market: &Pubkey) -> Pubkey {
let (pda, _bump) =
Pubkey::find_program_address(&[b"spline", market.as_ref()], &PHOENIX_PROGRAM_ID);
pda
}
pub fn get_ember_state_address() -> Pubkey {
let (pda, _bump) =
Pubkey::find_program_address(&[PHOENIX_PROGRAM_ID.as_ref(), b"state"], &EMBER_PROGRAM_ID);
pda
}
pub fn get_ember_vault_address() -> Pubkey {
let (pda, _bump) =
Pubkey::find_program_address(&[PHOENIX_PROGRAM_ID.as_ref(), b"vault"], &EMBER_PROGRAM_ID);
pda
}
pub fn get_global_vault_address(mint: &Pubkey) -> Pubkey {
let (pda, _bump) =
Pubkey::find_program_address(&[b"vault", mint.as_ref()], &PHOENIX_PROGRAM_ID);
pda
}
pub fn get_associated_token_address(owner: &Pubkey, mint: &Pubkey) -> Pubkey {
let (pda, _bump) = Pubkey::find_program_address(
&[owner.as_ref(), SPL_TOKEN_PROGRAM_ID.as_ref(), mint.as_ref()],
&ASSOCIATED_TOKEN_PROGRAM_ID,
);
pda
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_discriminant_computation() {
let limit_disc = place_limit_order_discriminant();
let market_disc = place_market_order_discriminant();
let cancel_disc = cancel_orders_by_id_discriminant();
assert_ne!(limit_disc, [0u8; 8]);
assert_ne!(market_disc, [0u8; 8]);
assert_ne!(cancel_disc, [0u8; 8]);
assert_ne!(limit_disc, market_disc);
assert_ne!(limit_disc, cancel_disc);
assert_ne!(market_disc, cancel_disc);
}
#[test]
fn test_spline_collection_pda_derivation() {
let market = Pubkey::new_unique();
let pda1 = get_spline_collection_address(&market);
let pda2 = get_spline_collection_address(&market);
assert_eq!(pda1, pda2);
let market2 = Pubkey::new_unique();
let pda3 = get_spline_collection_address(&market2);
assert_ne!(pda1, pda3);
}
#[test]
fn test_deposit_discriminants() {
let deposit_disc = deposit_funds_discriminant();
let ember_disc = ember_deposit_discriminant();
assert_ne!(deposit_disc, [0u8; 8]);
assert_ne!(ember_disc, [0u8; 8]);
assert_ne!(deposit_disc, ember_disc);
}
#[test]
fn test_register_trader_discriminant() {
let disc = register_trader_discriminant();
assert_ne!(disc, [0u8; 8]);
assert_ne!(disc, place_limit_order_discriminant());
assert_ne!(disc, place_market_order_discriminant());
assert_ne!(disc, cancel_orders_by_id_discriminant());
assert_ne!(disc, deposit_funds_discriminant());
assert_ne!(disc, withdraw_funds_discriminant());
}
#[test]
fn test_withdraw_discriminants() {
let withdraw_disc = withdraw_funds_discriminant();
let ember_withdraw_disc = ember_withdraw_discriminant();
let deposit_disc = deposit_funds_discriminant();
let ember_deposit_disc = ember_deposit_discriminant();
assert_ne!(withdraw_disc, [0u8; 8]);
assert_ne!(ember_withdraw_disc, [0u8; 8]);
assert_ne!(withdraw_disc, ember_withdraw_disc);
assert_ne!(withdraw_disc, deposit_disc);
assert_ne!(ember_withdraw_disc, ember_deposit_disc);
}
#[test]
fn test_ember_pda_derivation() {
let state1 = get_ember_state_address();
let state2 = get_ember_state_address();
assert_eq!(state1, state2);
let vault1 = get_ember_vault_address();
let vault2 = get_ember_vault_address();
assert_eq!(vault1, vault2);
assert_ne!(state1, vault1);
}
#[test]
fn test_global_vault_pda_derivation() {
let mint = Pubkey::new_unique();
let vault1 = get_global_vault_address(&mint);
let vault2 = get_global_vault_address(&mint);
assert_eq!(vault1, vault2);
let mint2 = Pubkey::new_unique();
let vault3 = get_global_vault_address(&mint2);
assert_ne!(vault1, vault3);
}
#[test]
fn test_stop_loss_pda_derivation() {
let trader_account = Pubkey::new_unique();
let asset_id: u64 = 42;
let pda1 = get_stop_loss_address(&trader_account, asset_id);
let pda2 = get_stop_loss_address(&trader_account, asset_id);
assert_eq!(pda1, pda2);
let pda3 = get_stop_loss_address(&trader_account, 99);
assert_ne!(pda1, pda3);
let trader2 = Pubkey::new_unique();
let pda4 = get_stop_loss_address(&trader2, asset_id);
assert_ne!(pda1, pda4);
}
#[test]
fn test_ata_derivation() {
let owner = Pubkey::new_unique();
let mint = Pubkey::new_unique();
let ata1 = get_associated_token_address(&owner, &mint);
let ata2 = get_associated_token_address(&owner, &mint);
assert_eq!(ata1, ata2);
let owner2 = Pubkey::new_unique();
let ata3 = get_associated_token_address(&owner2, &mint);
assert_ne!(ata1, ata3);
}
}