safe_token_2022/extension/memo_transfer/
mod.rs

1use {
2    crate::{
3        error::TokenError,
4        extension::{BaseStateWithExtensions, Extension, ExtensionType, StateWithExtensionsMut},
5        pod::PodBool,
6        state::Account,
7    },
8    bytemuck::{Pod, Zeroable},
9    solana_program::{
10        instruction::get_processed_sibling_instruction, program_error::ProgramError, pubkey::Pubkey,
11    },
12};
13
14/// Memo Transfer extension instructions
15pub mod instruction;
16
17/// Memo Transfer extension processor
18pub mod processor;
19
20/// Memo Transfer extension for Accounts
21#[repr(C)]
22#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
23pub struct MemoTransfer {
24    /// Require transfers into this account to be accompanied by a memo
25    pub require_incoming_transfer_memos: PodBool,
26}
27impl Extension for MemoTransfer {
28    const TYPE: ExtensionType = ExtensionType::MemoTransfer;
29}
30
31/// Determine if a memo is required for transfers into this account
32pub fn memo_required(account_state: &StateWithExtensionsMut<Account>) -> bool {
33    if let Ok(extension) = account_state.get_extension::<MemoTransfer>() {
34        return extension.require_incoming_transfer_memos.into();
35    }
36    false
37}
38
39/// Check if the previous sibling instruction is a memo
40pub fn check_previous_sibling_instruction_is_memo() -> Result<(), ProgramError> {
41    let is_memo_program = |program_id: &Pubkey| -> bool {
42        program_id == &safe_memo::id() || program_id == &safe_memo::v1::id()
43    };
44    let previous_instruction = get_processed_sibling_instruction(0);
45    match previous_instruction {
46        Some(instruction) if is_memo_program(&instruction.program_id) => {}
47        _ => {
48            return Err(TokenError::NoMemo.into());
49        }
50    }
51    Ok(())
52}