use crate::payload::Payload;
use borsh::{BorshDeserialize, BorshSerialize};
use mpl_token_metadata_context_derive::AccountContext;
use shank::ShankInstruction;
use solana_program::{
account_info::AccountInfo,
instruction::{AccountMeta, Instruction},
};
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
pub enum CreateOrUpdateArgs {
V1 {
serialized_rule_set: Vec<u8>,
},
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
pub enum ValidateArgs {
V1 {
operation: String,
payload: Payload,
update_rule_state: bool,
rule_set_revision: Option<usize>,
},
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
pub enum WriteToBufferArgs {
V1 {
serialized_rule_set: Vec<u8>,
overwrite: bool,
},
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
pub enum PuffRuleSetArgs {
V1 {
rule_set_name: String,
},
}
#[derive(Debug, Clone, ShankInstruction, AccountContext, BorshSerialize, BorshDeserialize)]
#[rustfmt::skip]
pub enum RuleSetInstruction {
#[account(0, signer, writable, name="payer", desc="Payer and creator of the RuleSet")]
#[account(1, writable, name="rule_set_pda", desc = "The PDA account where the RuleSet is stored")]
#[account(2, name = "system_program", desc = "System program")]
#[account(3, optional, name="buffer_pda", desc = "The buffer to copy a complete ruleset from")]
#[default_optional_accounts]
CreateOrUpdate(CreateOrUpdateArgs),
#[account(0, name="rule_set_pda", desc = "The PDA account where the RuleSet is stored")]
#[account(1, name="mint", desc="Mint of token asset")]
#[account(2, name = "system_program", desc = "System program")]
#[account(3, optional, signer, writable, name="payer", desc="Payer for RuleSet state PDA account")]
#[account(4, optional, signer, name="rule_authority", desc="Signing authority for any Rule state updates")]
#[account(5, optional, writable, name="rule_set_state_pda", desc = "The PDA account where any RuleSet state is stored")]
#[args(additional_rule_accounts: Vec<AccountMeta>)]
#[default_optional_accounts]
Validate(ValidateArgs),
#[account(0, signer, writable, name="payer", desc="Payer and creator of the RuleSet")]
#[account(1, writable, name="buffer_pda", desc = "The PDA account where the RuleSet buffer is stored")]
#[account(2, name = "system_program", desc = "System program")]
WriteToBuffer(WriteToBufferArgs),
#[account(0, signer, writable, name="payer", desc="Payer and creator of the RuleSet")]
#[account(1, writable, name="rule_set_pda", desc = "The PDA account where the RuleSet is stored")]
#[account(2, name = "system_program", desc = "System program")]
PuffRuleSet(PuffRuleSetArgs),
}
impl InstructionBuilder for builders::CreateOrUpdate {
fn instruction(&self) -> solana_program::instruction::Instruction {
let mut accounts = vec![
AccountMeta::new(self.payer, true),
AccountMeta::new(self.rule_set_pda, false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
];
if let Some(buffer_pda) = self.buffer_pda {
accounts.push(AccountMeta::new_readonly(buffer_pda, false));
} else {
accounts.push(AccountMeta::new_readonly(crate::ID, false));
}
Instruction {
program_id: crate::ID,
accounts,
data: RuleSetInstruction::CreateOrUpdate(self.args.clone())
.try_to_vec()
.unwrap(),
}
}
}
impl InstructionBuilder for builders::Validate {
fn instruction(&self) -> solana_program::instruction::Instruction {
let mut accounts = vec![
AccountMeta::new_readonly(self.rule_set_pda, false),
AccountMeta::new_readonly(self.mint, false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
];
if let Some(payer) = self.payer {
accounts.push(AccountMeta::new(payer, true));
} else {
accounts.push(AccountMeta::new_readonly(crate::ID, false));
}
if let Some(rule_authority) = self.rule_authority {
accounts.push(AccountMeta::new_readonly(rule_authority, true));
} else {
accounts.push(AccountMeta::new_readonly(crate::ID, false));
}
if let Some(rule_set_state_pda) = self.rule_set_state_pda {
accounts.push(AccountMeta::new(rule_set_state_pda, false));
} else {
accounts.push(AccountMeta::new_readonly(crate::ID, false));
}
accounts.extend(self.additional_rule_accounts.clone());
Instruction {
program_id: crate::ID,
accounts,
data: RuleSetInstruction::Validate(self.args.clone())
.try_to_vec()
.unwrap(),
}
}
}
impl InstructionBuilder for builders::WriteToBuffer {
fn instruction(&self) -> solana_program::instruction::Instruction {
let accounts = vec![
AccountMeta::new(self.payer, true),
AccountMeta::new(self.buffer_pda, false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
];
Instruction {
program_id: crate::ID,
accounts,
data: RuleSetInstruction::WriteToBuffer(self.args.clone())
.try_to_vec()
.unwrap(),
}
}
}
impl InstructionBuilder for builders::PuffRuleSet {
fn instruction(&self) -> solana_program::instruction::Instruction {
let accounts = vec![
AccountMeta::new(self.payer, true),
AccountMeta::new(self.rule_set_pda, false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
];
Instruction {
program_id: crate::ID,
accounts,
data: RuleSetInstruction::PuffRuleSet(self.args.clone())
.try_to_vec()
.unwrap(),
}
}
}
pub struct Context<'a, T> {
pub accounts: T,
pub remaining_accounts: Vec<&'a AccountInfo<'a>>,
}
pub trait InstructionBuilder {
fn instruction(&self) -> solana_program::instruction::Instruction;
}