solmail_program/instructions/credits/
deposit.rs1use pinocchio::{
2 account_info::AccountInfo,
3 instruction::Signer,
4 program_error::ProgramError,
5 pubkey::{find_program_address, Pubkey},
6 seeds,
7 sysvars::{rent::Rent, Sysvar},
8 ProgramResult,
9};
10use pinocchio_system::instructions::{CreateAccount, Transfer};
11
12use crate::{
13 constants::{CREDITS_SEED, CREDITS_VAULT_SOL_SEED, MIN_ESCROW_LAMPORTS},
14 error::SolMailError,
15 state::credits::{UserCredits, USER_CREDITS_SIZE},
16};
17
18pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
29 if data.len() < 8 {
31 return Err(ProgramError::InvalidInstructionData);
32 }
33
34 let amount = u64::from_le_bytes(data[0..8].try_into().unwrap());
35
36 if amount < MIN_ESCROW_LAMPORTS {
38 return Err(SolMailError::AmountBelowMinimum.into());
39 }
40
41 let [user, user_credits, credits_vault, _system_program] = accounts else {
43 return Err(ProgramError::NotEnoughAccountKeys);
44 };
45
46 if !user.is_signer() {
48 return Err(SolMailError::MissingRequiredSignature.into());
49 }
50
51 let user_key_bytes = user.key();
53 let (credits_pda, credits_bump) =
54 find_program_address(&[CREDITS_SEED, user_key_bytes.as_ref()], program_id);
55
56 if user_credits.key() != &credits_pda {
57 return Err(SolMailError::InvalidPda.into());
58 }
59
60 let (vault_pda, vault_bump) =
62 find_program_address(&[CREDITS_VAULT_SOL_SEED], program_id);
63
64 if credits_vault.key() != &vault_pda {
65 return Err(SolMailError::InvalidPda.into());
66 }
67
68 let is_new_account = user_credits.data_len() == 0;
70
71 if is_new_account {
72 let rent = Rent::get()?;
74 let rent_lamports = rent.minimum_balance(USER_CREDITS_SIZE);
75
76 let credits_bump_ref = &[credits_bump];
78 let credits_seeds = seeds!(CREDITS_SEED, user_key_bytes.as_ref(), credits_bump_ref);
79 let credits_signer = Signer::from(&credits_seeds);
80
81 CreateAccount {
83 from: user,
84 to: user_credits,
85 lamports: rent_lamports,
86 space: USER_CREDITS_SIZE as u64,
87 owner: program_id,
88 }
89 .invoke_signed(&[credits_signer])?;
90
91 let credits_data = unsafe { user_credits.borrow_mut_data_unchecked() };
93 let credits = UserCredits::from_bytes_mut(credits_data)?;
94 credits.owner.copy_from_slice(user.key().as_ref());
95 credits.sol_balance = 0;
96 credits.usdc_balance = 0;
97 credits.bump = credits_bump;
98 }
99
100 if credits_vault.lamports() == 0 {
102 let rent = Rent::get()?;
104 let rent_lamports = rent.minimum_balance(0);
105
106 let vault_bump_ref = &[vault_bump];
108 let vault_seeds = seeds!(CREDITS_VAULT_SOL_SEED, vault_bump_ref);
109 let vault_signer = Signer::from(&vault_seeds);
110
111 CreateAccount {
112 from: user,
113 to: credits_vault,
114 lamports: rent_lamports,
115 space: 0,
116 owner: program_id,
117 }
118 .invoke_signed(&[vault_signer])?;
119 }
120
121 Transfer {
123 from: user,
124 to: credits_vault,
125 lamports: amount,
126 }
127 .invoke()?;
128
129 let credits_data = unsafe { user_credits.borrow_mut_data_unchecked() };
131 let credits = UserCredits::from_bytes_mut(credits_data)?;
132 credits.add_sol(amount)?;
133
134 Ok(())
135}