1use crate::payload::Payload;
2use borsh::{BorshDeserialize, BorshSerialize};
3use mpl_token_metadata_context_derive::AccountContext;
4use shank::ShankInstruction;
5use solana_program::{
6 account_info::AccountInfo,
7 instruction::{AccountMeta, Instruction},
8};
9
10#[repr(C)]
11#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
12pub enum CreateOrUpdateArgs {
14 V1 {
16 serialized_rule_set: Vec<u8>,
19 },
20}
21
22#[repr(C)]
23#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
24pub enum ValidateArgs {
26 V1 {
28 operation: String,
30 payload: Payload,
32 update_rule_state: bool,
34 rule_set_revision: Option<usize>,
36 },
37}
38
39#[repr(C)]
40#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
41pub enum WriteToBufferArgs {
43 V1 {
45 serialized_rule_set: Vec<u8>,
47 overwrite: bool,
49 },
50}
51
52#[repr(C)]
53#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
54pub enum PuffRuleSetArgs {
56 V1 {
58 rule_set_name: String,
60 },
61}
62
63#[derive(Debug, Clone, ShankInstruction, AccountContext, BorshSerialize, BorshDeserialize)]
64#[rustfmt::skip]
65pub enum RuleSetInstruction {
67 #[account(0, signer, writable, name="payer", desc="Payer and creator of the RuleSet")]
69 #[account(1, writable, name="rule_set_pda", desc = "The PDA account where the RuleSet is stored")]
70 #[account(2, name = "system_program", desc = "System program")]
71 #[account(3, optional, name="buffer_pda", desc = "The buffer to copy a complete ruleset from")]
72 CreateOrUpdate(CreateOrUpdateArgs),
73
74 #[account(0, name="rule_set_pda", desc = "The PDA account where the RuleSet is stored")]
81 #[account(1, name="mint", desc="Mint of token asset")]
82 #[account(2, name = "system_program", desc = "System program")]
83 #[account(3, optional, signer, writable, name="payer", desc="Payer for RuleSet state PDA account")]
84 #[account(4, optional, signer, name="rule_authority", desc="Signing authority for any Rule state updates")]
85 #[account(5, optional, writable, name="rule_set_state_pda", desc = "The PDA account where any RuleSet state is stored")]
86 #[args(additional_rule_accounts: Vec<AccountMeta>)]
87 Validate(ValidateArgs),
88
89 #[account(0, signer, writable, name="payer", desc="Payer and creator of the RuleSet")]
92 #[account(1, writable, name="buffer_pda", desc = "The PDA account where the RuleSet buffer is stored")]
93 #[account(2, name = "system_program", desc = "System program")]
94 WriteToBuffer(WriteToBufferArgs),
95
96 #[account(0, signer, writable, name="payer", desc="Payer and creator of the RuleSet")]
99 #[account(1, writable, name="rule_set_pda", desc = "The PDA account where the RuleSet is stored")]
100 #[account(2, name = "system_program", desc = "System program")]
101 PuffRuleSet(PuffRuleSetArgs),
102}
103
104impl InstructionBuilder for builders::CreateOrUpdate {
106 fn instruction(&self) -> solana_program::instruction::Instruction {
107 let mut accounts = vec![
108 AccountMeta::new(self.payer, true),
109 AccountMeta::new(self.rule_set_pda, false),
110 AccountMeta::new_readonly(solana_program::system_program::id(), false),
111 ];
112
113 if let Some(buffer_pda) = self.buffer_pda {
114 accounts.push(AccountMeta::new_readonly(buffer_pda, false));
115 } else {
116 accounts.push(AccountMeta::new_readonly(crate::ID, false));
117 }
118
119 Instruction {
120 program_id: crate::ID,
121 accounts,
122 data: RuleSetInstruction::CreateOrUpdate(self.args.clone())
123 .try_to_vec()
124 .unwrap(),
125 }
126 }
127}
128
129impl InstructionBuilder for builders::Validate {
131 fn instruction(&self) -> solana_program::instruction::Instruction {
132 let mut accounts = vec![
133 AccountMeta::new_readonly(self.rule_set_pda, false),
134 AccountMeta::new_readonly(self.mint, false),
135 AccountMeta::new_readonly(solana_program::system_program::id(), false),
136 ];
137
138 if let Some(payer) = self.payer {
140 accounts.push(AccountMeta::new(payer, true));
141 } else {
142 accounts.push(AccountMeta::new_readonly(crate::ID, false));
143 }
144
145 if let Some(rule_authority) = self.rule_authority {
147 accounts.push(AccountMeta::new_readonly(rule_authority, true));
148 } else {
149 accounts.push(AccountMeta::new_readonly(crate::ID, false));
150 }
151
152 if let Some(rule_set_state_pda) = self.rule_set_state_pda {
154 accounts.push(AccountMeta::new(rule_set_state_pda, false));
155 } else {
156 accounts.push(AccountMeta::new_readonly(crate::ID, false));
157 }
158
159 accounts.extend(self.additional_rule_accounts.clone());
160
161 Instruction {
162 program_id: crate::ID,
163 accounts,
164 data: RuleSetInstruction::Validate(self.args.clone())
165 .try_to_vec()
166 .unwrap(),
167 }
168 }
169}
170
171impl InstructionBuilder for builders::WriteToBuffer {
173 fn instruction(&self) -> solana_program::instruction::Instruction {
174 let accounts = vec![
175 AccountMeta::new(self.payer, true),
176 AccountMeta::new(self.buffer_pda, false),
177 AccountMeta::new_readonly(solana_program::system_program::id(), false),
178 ];
179
180 Instruction {
181 program_id: crate::ID,
182 accounts,
183 data: RuleSetInstruction::WriteToBuffer(self.args.clone())
184 .try_to_vec()
185 .unwrap(),
186 }
187 }
188}
189
190impl InstructionBuilder for builders::PuffRuleSet {
192 fn instruction(&self) -> solana_program::instruction::Instruction {
193 let accounts = vec![
194 AccountMeta::new(self.payer, true),
195 AccountMeta::new(self.rule_set_pda, false),
196 AccountMeta::new_readonly(solana_program::system_program::id(), false),
197 ];
198
199 Instruction {
200 program_id: crate::ID,
201 accounts,
202 data: RuleSetInstruction::PuffRuleSet(self.args.clone())
203 .try_to_vec()
204 .unwrap(),
205 }
206 }
207}
208
209pub struct Context<'a, T> {
211 pub accounts: T,
213 pub remaining_accounts: Vec<&'a AccountInfo<'a>>,
215}
216
217pub trait InstructionBuilder {
219 fn instruction(&self) -> solana_program::instruction::Instruction;
221}