Skip to main content

solmail_program/state/
credits.rs

1use crate::error::SolMailError;
2
3/// Size of the UserCredits account in bytes
4pub const USER_CREDITS_SIZE: usize = 49;
5
6/// User prepaid credits account
7#[repr(C, packed)]
8#[derive(Clone, Copy, Debug)]
9pub struct UserCredits {
10    /// Public key of the wallet owner
11    pub owner: [u8; 32],
12    /// SOL balance in lamports
13    pub sol_balance: u64,
14    /// USDC balance (6 decimals)
15    pub usdc_balance: u64,
16    /// PDA bump seed
17    pub bump: u8,
18}
19
20const _: () = assert!(core::mem::size_of::<UserCredits>() == USER_CREDITS_SIZE);
21
22impl UserCredits {
23    /// Zero-copy parse from account data
24    pub fn from_bytes(data: &[u8]) -> Result<&Self, SolMailError> {
25        if data.len() < USER_CREDITS_SIZE {
26            return Err(SolMailError::InvalidInstructionData);
27        }
28        // SAFETY: Data is properly sized and repr(C, packed) ensures predictable layout
29        Ok(unsafe { &*(data.as_ptr() as *const Self) })
30    }
31
32    /// Zero-copy mutable parse from account data
33    pub fn from_bytes_mut(data: &mut [u8]) -> Result<&mut Self, SolMailError> {
34        if data.len() < USER_CREDITS_SIZE {
35            return Err(SolMailError::InvalidInstructionData);
36        }
37        // SAFETY: Data is properly sized and repr(C, packed) ensures predictable layout
38        Ok(unsafe { &mut *(data.as_mut_ptr() as *mut Self) })
39    }
40
41    /// Add SOL credits
42    pub fn add_sol(&mut self, amount: u64) -> Result<(), SolMailError> {
43        self.sol_balance = self
44            .sol_balance
45            .checked_add(amount)
46            .ok_or(SolMailError::Overflow)?;
47        Ok(())
48    }
49
50    /// Subtract SOL credits
51    pub fn sub_sol(&mut self, amount: u64) -> Result<(), SolMailError> {
52        if self.sol_balance < amount {
53            return Err(SolMailError::InsufficientFunds);
54        }
55        self.sol_balance -= amount;
56        Ok(())
57    }
58
59    /// Add USDC credits
60    pub fn add_usdc(&mut self, amount: u64) -> Result<(), SolMailError> {
61        self.usdc_balance = self
62            .usdc_balance
63            .checked_add(amount)
64            .ok_or(SolMailError::Overflow)?;
65        Ok(())
66    }
67
68    /// Subtract USDC credits
69    pub fn sub_usdc(&mut self, amount: u64) -> Result<(), SolMailError> {
70        if self.usdc_balance < amount {
71            return Err(SolMailError::InsufficientFunds);
72        }
73        self.usdc_balance -= amount;
74        Ok(())
75    }
76}