solmail_program/instructions/escrow/
refund.rs1use pinocchio::{
2 account_info::AccountInfo,
3 program_error::ProgramError,
4 pubkey::{find_program_address, Pubkey},
5 sysvars::{clock::Clock, Sysvar},
6 ProgramResult,
7};
8
9use crate::{
10 constants::{ESCROW_SEED, ESCROW_VAULT_SEED},
11 error::SolMailError,
12 state::escrow::EscrowOrder,
13};
14
15pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
27 if data.len() < 16 {
29 return Err(ProgramError::InvalidInstructionData);
30 }
31
32 let mail_id_low = u64::from_le_bytes(data[0..8].try_into().unwrap());
33 let mail_id_high = u64::from_le_bytes(data[8..16].try_into().unwrap());
34
35 let [payer, escrow_state, escrow_vault, _system_program] = accounts else {
37 return Err(ProgramError::NotEnoughAccountKeys);
38 };
39
40 if !payer.is_signer() {
42 return Err(SolMailError::MissingRequiredSignature.into());
43 }
44
45 let mut mail_id_bytes = [0u8; 16];
47 mail_id_bytes[..8].copy_from_slice(&mail_id_low.to_le_bytes());
48 mail_id_bytes[8..].copy_from_slice(&mail_id_high.to_le_bytes());
49
50 let (escrow_pda, _) =
52 find_program_address(&[ESCROW_SEED, &mail_id_bytes], program_id);
53
54 if escrow_state.key() != &escrow_pda {
55 return Err(SolMailError::InvalidPda.into());
56 }
57
58 let escrow_data = unsafe { escrow_state.borrow_data_unchecked() };
60 let escrow = EscrowOrder::from_bytes(escrow_data)?;
61
62 if payer.key().as_ref() != &escrow.payer {
64 return Err(SolMailError::InvalidPayer.into());
65 }
66
67 if escrow.delivered {
69 return Err(SolMailError::AlreadyDelivered.into());
70 }
71
72 let clock = Clock::get()?;
74 if !escrow.is_timed_out(clock.unix_timestamp) {
75 return Err(SolMailError::TimeoutNotReached.into());
76 }
77
78 let (vault_pda, _) =
80 find_program_address(&[ESCROW_VAULT_SEED, &mail_id_bytes], program_id);
81
82 if escrow_vault.key() != &vault_pda {
83 return Err(SolMailError::InvalidPda.into());
84 }
85
86 let state_data = unsafe { escrow_state.borrow_mut_data_unchecked() };
88 state_data.iter_mut().for_each(|b| *b = 0);
89
90 let vault_lamports = escrow_vault.lamports();
92 unsafe {
93 *escrow_vault.borrow_mut_lamports_unchecked() = 0;
94 *payer.borrow_mut_lamports_unchecked() += vault_lamports;
95 }
96
97 let escrow_lamports = escrow_state.lamports();
99 unsafe {
100 *escrow_state.borrow_mut_lamports_unchecked() = 0;
101 *payer.borrow_mut_lamports_unchecked() += escrow_lamports;
102 }
103
104 Ok(())
105}