Skip to main content

spl_memo/
processor.rs

1//! Program state processor
2
3use {
4    miraland_program::{
5        account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError,
6        pubkey::Pubkey,
7    },
8    std::str::from_utf8,
9};
10
11/// Instruction processor
12pub fn process_instruction(
13    _program_id: &Pubkey,
14    accounts: &[AccountInfo],
15    input: &[u8],
16) -> ProgramResult {
17    let account_info_iter = &mut accounts.iter();
18    let mut missing_required_signature = false;
19    for account_info in account_info_iter {
20        if let Some(address) = account_info.signer_key() {
21            msg!("Signed by {:?}", address);
22        } else {
23            missing_required_signature = true;
24        }
25    }
26    if missing_required_signature {
27        return Err(ProgramError::MissingRequiredSignature);
28    }
29
30    let memo = from_utf8(input).map_err(|err| {
31        msg!("Invalid UTF-8, from byte {}", err.valid_up_to());
32        ProgramError::InvalidInstructionData
33    })?;
34    msg!("Memo (len {}): {:?}", memo.len(), memo);
35
36    Ok(())
37}
38
39#[cfg(test)]
40mod tests {
41    use {
42        super::*,
43        miraland_program::{
44            account_info::IntoAccountInfo, program_error::ProgramError, pubkey::Pubkey,
45        },
46        miraland_sdk::account::Account,
47    };
48
49    #[test]
50    fn test_utf8_memo() {
51        let program_id = Pubkey::new_from_array([0; 32]);
52
53        let string = b"letters and such";
54        assert_eq!(Ok(()), process_instruction(&program_id, &[], string));
55
56        let emoji = "🐆".as_bytes();
57        let bytes = [0xF0, 0x9F, 0x90, 0x86];
58        assert_eq!(emoji, bytes);
59        assert_eq!(Ok(()), process_instruction(&program_id, &[], emoji));
60
61        let mut bad_utf8 = bytes;
62        bad_utf8[3] = 0xFF; // Invalid UTF-8 byte
63        assert_eq!(
64            Err(ProgramError::InvalidInstructionData),
65            process_instruction(&program_id, &[], &bad_utf8)
66        );
67    }
68
69    #[test]
70    fn test_signers() {
71        let program_id = Pubkey::new_from_array([0; 32]);
72        let memo = "🐆".as_bytes();
73
74        let pubkey0 = Pubkey::new_unique();
75        let pubkey1 = Pubkey::new_unique();
76        let pubkey2 = Pubkey::new_unique();
77        let mut account0 = Account::default();
78        let mut account1 = Account::default();
79        let mut account2 = Account::default();
80
81        let signed_account_infos = vec![
82            (&pubkey0, true, &mut account0).into_account_info(),
83            (&pubkey1, true, &mut account1).into_account_info(),
84            (&pubkey2, true, &mut account2).into_account_info(),
85        ];
86        assert_eq!(
87            Ok(()),
88            process_instruction(&program_id, &signed_account_infos, memo)
89        );
90
91        assert_eq!(Ok(()), process_instruction(&program_id, &[], memo));
92
93        let unsigned_account_infos = vec![
94            (&pubkey0, false, &mut account0).into_account_info(),
95            (&pubkey1, false, &mut account1).into_account_info(),
96            (&pubkey2, false, &mut account2).into_account_info(),
97        ];
98        assert_eq!(
99            Err(ProgramError::MissingRequiredSignature),
100            process_instruction(&program_id, &unsigned_account_infos, memo)
101        );
102
103        let partially_signed_account_infos = vec![
104            (&pubkey0, true, &mut account0).into_account_info(),
105            (&pubkey1, false, &mut account1).into_account_info(),
106            (&pubkey2, true, &mut account2).into_account_info(),
107        ];
108        assert_eq!(
109            Err(ProgramError::MissingRequiredSignature),
110            process_instruction(&program_id, &partially_signed_account_infos, memo)
111        );
112    }
113}