gmsol_utils/
instruction.rs1use anchor_lang::{
2 prelude::{zero_copy, AccountMeta, Pubkey},
3 solana_program::instruction::Instruction,
4};
5
6const MAX_FLAGS: usize = 8;
7
8#[derive(Debug, thiserror::Error)]
10pub enum InstructionError {
11 #[error("failed to get wallet")]
13 FailedToGetWallet,
14}
15
16#[zero_copy]
18pub struct InstructionAccount {
19 pub flags: InstructionAccountFlagContainer,
21 pub pubkey: Pubkey,
23}
24
25impl crate::InitSpace for InstructionAccount {
26 const INIT_SPACE: usize = std::mem::size_of::<Self>();
27}
28
29#[derive(num_enum::IntoPrimitive)]
31#[repr(u8)]
32pub enum InstructionAccountFlag {
33 Signer,
35 Writable,
37 }
39
40crate::flags!(InstructionAccountFlag, MAX_FLAGS, u8);
41
42impl<'a> From<&'a InstructionAccount> for AccountMeta {
43 fn from(a: &'a InstructionAccount) -> Self {
44 Self {
45 pubkey: a.pubkey,
46 is_signer: a.flags.get_flag(InstructionAccountFlag::Signer),
47 is_writable: a.flags.get_flag(InstructionAccountFlag::Writable),
48 }
49 }
50}
51
52pub trait InstructionAccess {
54 fn wallet(&self) -> Result<Pubkey, InstructionError>;
56
57 fn program_id(&self) -> &Pubkey;
59
60 fn data(&self) -> &[u8];
62
63 fn num_accounts(&self) -> usize;
65
66 fn accounts(&self) -> impl Iterator<Item = &InstructionAccount>;
68
69 fn to_instruction(
71 &self,
72 mark_executor_wallet_as_signer: bool,
73 ) -> Result<Instruction, InstructionError> {
74 let mut accounts = self
75 .accounts()
76 .map(From::from)
77 .collect::<Vec<AccountMeta>>();
78
79 if mark_executor_wallet_as_signer {
82 let executor_wallet = self.wallet()?;
83 accounts
84 .iter_mut()
85 .filter(|a| a.pubkey == executor_wallet)
86 .for_each(|a| a.is_signer = true);
87 }
88
89 Ok(Instruction {
90 program_id: *self.program_id(),
91 accounts,
92 data: self.data().to_vec(),
93 })
94 }
95}