#[cfg(feature = "anchor")]
use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize};
#[cfg(not(feature = "anchor"))]
use borsh::{BorshDeserialize, BorshSerialize};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MetaEntry {
pub pubkey: solana_program::pubkey::Pubkey,
pub is_signer: bool,
pub is_writable: bool,
}
pub struct DynamicInstruction {
pub target_program_id: solana_program::pubkey::Pubkey,
pub data: Vec<u8>,
pub account_metas: Vec<MetaEntry>,
}
impl DynamicInstruction {
pub fn instruction(&self) -> solana_program::instruction::Instruction {
self.instruction_with_remaining_accounts(&[])
}
pub fn instruction_with_remaining_accounts(
&self,
remaining_accounts: &[solana_program::instruction::AccountMeta],
) -> solana_program::instruction::Instruction {
let mut accounts = Vec::with_capacity(self.account_metas.len() + remaining_accounts.len());
for meta in &self.account_metas {
accounts.push(solana_program::instruction::AccountMeta {
pubkey: meta.pubkey,
is_signer: meta.is_signer,
is_writable: meta.is_writable,
});
}
accounts.extend_from_slice(remaining_accounts);
solana_program::instruction::Instruction {
program_id: self.target_program_id,
accounts,
data: self.data.clone(),
}
}
}
#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MiddlewareArgs {
pub instruction_data: Vec<u8>,
}
#[derive(Default)]
pub struct MiddlewareBuilder {
target_program_id: Option<solana_program::pubkey::Pubkey>,
data: Option<Vec<u8>>,
account_metas: Vec<MetaEntry>,
__remaining_accounts: Vec<solana_program::instruction::AccountMeta>,
}
impl MiddlewareBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn target_program_id(mut self, target_program_id: solana_program::pubkey::Pubkey) -> Self {
self.target_program_id = Some(target_program_id);
self
}
pub fn data(mut self, data: Vec<u8>) -> Self {
self.data = Some(data);
self
}
pub fn add_account_meta(
mut self,
pubkey: solana_program::pubkey::Pubkey,
is_signer: bool,
is_writable: bool,
) -> Self {
self.account_metas.push(MetaEntry {
pubkey,
is_signer,
is_writable,
});
self
}
pub fn add_remaining_account(
&mut self,
account: solana_program::instruction::AccountMeta,
) -> &mut Self {
self.__remaining_accounts.push(account);
self
}
pub fn add_remaining_accounts(
&mut self,
accounts: &[solana_program::instruction::AccountMeta],
) -> &mut Self {
self.__remaining_accounts.extend_from_slice(accounts);
self
}
pub fn instruction(&self) -> solana_program::instruction::Instruction {
let dynamic = DynamicInstruction {
target_program_id: self
.target_program_id
.expect("target_program_id is required"),
data: self.data.clone().expect("data is required"),
account_metas: self.account_metas.clone(),
};
dynamic.instruction_with_remaining_accounts(&self.__remaining_accounts)
}
}