sla-escrow-api 0.3.0

SLA-Escrow: Service Level Agreement Enforcer for AI Agents
Documentation
mod authority_transfer;
mod bank;
mod config;
mod escrow;
mod payment;

pub use authority_transfer::*;
pub use bank::*;
pub use config::*;
pub use escrow::*;
pub use payment::*;

use steel::*;

use crate::consts::*;

#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
pub enum EscrowAccount {
    Bank = 100,
    Config = 101,
    Escrow = 102,
    Payment = 103,
    AuthorityTransfer = 104,
}

/// Derive the PDA of the bank account.
pub fn bank_pda() -> (Pubkey, u8) {
    Pubkey::find_program_address(&[BANK], &crate::id())
}

/// Derive the PDA of the config account.
pub fn config_pda() -> (Pubkey, u8) {
    Pubkey::find_program_address(&[CONFIG], &crate::id())
}

/// Derive the PDA of an escrow account.
pub fn escrow_pda(mint: Pubkey, bank: Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(&[ESCROW, mint.as_ref(), bank.as_ref()], &crate::id())
}

/// Derive the PDA of a payment account.
pub fn payment_pda(payment_uid: &str, bank: Pubkey) -> (Pubkey, u8) {
    let payment_uid = normalize_payment_uid(payment_uid);
    payment_pda_from_bytes(&payment_uid, bank)
}

/// Normalize a payment UID string into the canonical 32-byte seed format.
pub fn normalize_payment_uid(payment_uid: &str) -> [u8; 32] {
    let mut uid_bytes = [0u8; 32];
    let uid_str = payment_uid.replace('-', "");
    let uid_bytes_str = uid_str.as_bytes();
    let len = uid_bytes_str.len().min(32);
    uid_bytes[..len].copy_from_slice(&uid_bytes_str[..len]);
    uid_bytes
}

/// Derive the PDA of a payment account from its canonical 32-byte seed payload.
pub fn payment_pda_from_bytes(payment_uid: &[u8; 32], bank: Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(&[PAYMENT, payment_uid, bank.as_ref()], &crate::id())
}

/// Derive the PDA of a SOL storage account.
/// This account holds SOL for escrows and can be used for transfers (no data, just lamports).
pub fn sol_storage_pda(mint: Pubkey, bank: Pubkey, escrow: Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(
        &[SOL_STORAGE, mint.as_ref(), bank.as_ref(), escrow.as_ref()],
        &crate::id(),
    )
}

/// Derive the PDA of an authority transfer proposal.
pub fn authority_transfer_pda(bank: Pubkey) -> (Pubkey, u8) {
    Pubkey::find_program_address(&[AUTHORITY_TRANSFER, bank.as_ref()], &crate::id())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn normalized_and_raw_payment_uid_match() {
        let bank = Pubkey::new_unique();
        let uid = "123e4567-e89b-12d3-a456-426614174000";

        let normalized = normalize_payment_uid(uid);
        let from_str = payment_pda(uid, bank);
        let from_bytes = payment_pda_from_bytes(&normalized, bank);

        assert_eq!(from_str, from_bytes);
    }
}