use solana_sdk::{instruction::Instruction, signature::Keypair};
use wp_solana_tx::TransactionBuilder;
#[derive(Debug, Default)]
pub struct PlannedTransaction {
pub instructions: Vec<Instruction>,
pub additional_signers: Vec<Keypair>,
}
impl PlannedTransaction {
pub fn new(instructions: Vec<Instruction>, additional_signers: Vec<Keypair>) -> Self {
Self { instructions, additional_signers }
}
pub fn is_empty(&self) -> bool {
self.instructions.is_empty()
}
pub fn into_transaction_builder(self) -> TransactionBuilder {
TransactionBuilder::with_components(self.instructions, self.additional_signers)
}
}
impl From<PlannedTransaction> for TransactionBuilder {
fn from(planned: PlannedTransaction) -> Self {
planned.into_transaction_builder()
}
}
pub trait Plannable {
type Snapshot;
type Params;
type Error: std::error::Error + Send + Sync + 'static;
fn plan(
snapshot: &Self::Snapshot,
params: Self::Params,
) -> Result<PlannedTransaction, Self::Error>;
}
#[cfg(test)]
mod tests {
use solana_sdk::{
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
};
use super::*;
fn ix() -> Instruction {
Instruction {
program_id: Pubkey::new_unique(),
accounts: vec![AccountMeta::new(Pubkey::new_unique(), false)],
data: vec![9, 9, 9],
}
}
#[test]
fn default_is_empty() {
let p = PlannedTransaction::default();
assert!(p.is_empty());
}
#[test]
fn new_populates_fields() {
let p = PlannedTransaction::new(vec![ix()], vec![Keypair::new()]);
assert!(!p.is_empty());
assert_eq!(p.instructions.len(), 1);
assert_eq!(p.additional_signers.len(), 1);
}
#[test]
fn into_transaction_builder_round_trip() {
let p = PlannedTransaction::new(vec![ix(), ix()], vec![]);
let b: TransactionBuilder = p.into();
assert_eq!(b.instruction_count(), 2);
assert_eq!(b.signer_count(), 0);
}
#[test]
fn plannable_trait_can_be_implemented_on_a_local_handle() {
struct NoopPlan;
struct NoopSnapshot;
struct NoopParams;
#[derive(Debug, thiserror::Error)]
#[error("noop")]
struct NoopError;
impl Plannable for NoopPlan {
type Error = NoopError;
type Params = NoopParams;
type Snapshot = NoopSnapshot;
fn plan(
_snapshot: &Self::Snapshot,
_params: Self::Params,
) -> Result<PlannedTransaction, Self::Error> {
Ok(PlannedTransaction::new(vec![ix()], vec![]))
}
}
let planned = NoopPlan::plan(&NoopSnapshot, NoopParams).unwrap();
assert_eq!(planned.instructions.len(), 1);
}
}