use arrayref::{array_ref, array_refs};
use solana_program::{
instruction::AccountMeta, instruction::Instruction, program_error::ProgramError, pubkey::Pubkey,
};
use crate::state;
pub enum YesNoInstruction<'a> {
CreateQuestion { name: &'a str, deadline: u64 },
Bet { yesno: u8 },
CloseQuestion,
}
impl<'a> YesNoInstruction<'a> {
pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
use ProgramError::InvalidInstructionData;
let (&tag, rest) = input.split_first().ok_or(InvalidInstructionData)?;
Ok(match tag {
0 => {
let rest = array_ref!(rest, 0, 264);
let (name, deadline) = array_refs!(rest, 256, 8);
let name = state::unpack_str(name).unwrap();
let deadline = u64::from_le_bytes(*deadline);
Self::CreateQuestion { name, deadline }
}
1 => {
let yesno = rest[0];
Self::Bet { yesno }
}
2 => {
Self::CloseQuestion
}
_ => return Err(InvalidInstructionData),
})
}
pub fn pack(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::with_capacity(100);
match *self {
Self::CreateQuestion { name, deadline } => {
buf.push(0);
let mut name_bytes: [u8; 256] = [0; 256];
state::pack_str(name, &mut name_bytes).unwrap();
buf.extend_from_slice(&name_bytes);
buf.extend_from_slice(&deadline.to_le_bytes());
}
Self::Bet { yesno } => {
buf.push(1);
buf.push(yesno);
}
Self::CloseQuestion {} => {
buf.push(2);
}
}
buf
}
}
pub fn create_question(
program_id: &Pubkey,
question: &Pubkey,
creator: &Pubkey,
mint: &Pubkey,
creator_spl: &Pubkey,
mint_owner: &Pubkey,
name: &str,
deadline: u64,
) -> Result<Instruction, ProgramError> {
let data = YesNoInstruction::CreateQuestion { name, deadline }.pack();
let accounts = vec![
AccountMeta::new(*question, false),
AccountMeta::new(*creator, true),
AccountMeta::new(*mint, false),
AccountMeta::new(*mint, false),
AccountMeta::new(*creator_spl, false),
AccountMeta::new(*mint_owner, true),
AccountMeta::new_readonly(spl_token::id(), false),
];
Ok(Instruction {
program_id: *program_id,
accounts,
data,
})
}
pub fn create_bet(
program_id: &Pubkey,
bet: &Pubkey,
question: &Pubkey,
bet_maker: &Pubkey,
yesno: u8,
) -> Result<Instruction, ProgramError> {
let data = YesNoInstruction::Bet { yesno }.pack();
let accounts = vec![
AccountMeta::new(*bet, false),
AccountMeta::new(*question, false),
AccountMeta::new(*bet_maker, true),
];
Ok(Instruction {
program_id: *program_id,
accounts,
data,
})
}