use cow_settlement_interface::{
instruction::{
add_solver::AddSolverInput,
cancel_order::CancelOrderInput,
create_buffer::CreateBufferInput,
create_order::CreateOrderInput,
create_settlement_owned_order::CreateSettlementOwnedOrderInput,
initialize::InitializeInput,
reclaim_buffer::ReclaimBufferInput,
reclaim_order::ReclaimOrderInput,
remove_solver::RemoveSolverInput,
settle::{BeginSettleInput, FinalizeSettleInput},
transfer_authority::TransferAuthorityInput,
withdraw_native_sol::WithdrawNativeSolInput,
InstructionInputParsing,
},
recover_discriminator, SettlementInstruction,
};
use solana_program_error::ProgramError;
pub enum ParsedInstruction<'a, A> {
Initialize(InitializeInput<'a, A>),
CreateOrder(CreateOrderInput<'a, A>),
CancelOrder(CancelOrderInput<'a, A>),
CreateSettlementOwnedOrder(CreateSettlementOwnedOrderInput<'a, A>),
CreateBuffer(CreateBufferInput<'a, A>),
BeginSettle(BeginSettleInput<'a, A>),
FinalizeSettle(FinalizeSettleInput<'a, A>),
ReclaimOrder(ReclaimOrderInput<'a, A>),
ReclaimBuffer(ReclaimBufferInput<'a, A>),
TransferAuthority(TransferAuthorityInput<'a, A>),
AddSolver(AddSolverInput<'a, A>),
RemoveSolver(RemoveSolverInput<'a, A>),
WithdrawNativeSol(WithdrawNativeSolInput<'a, A>),
}
pub fn parse_instruction<'a, A>(
instruction_data: &'a [u8],
accounts: &'a [A],
) -> Result<ParsedInstruction<'a, A>, ProgramError> {
let (discriminator, remaining_data) = recover_discriminator(instruction_data)?;
Ok(match discriminator {
SettlementInstruction::Initialize => {
ParsedInstruction::Initialize(InitializeInput::parse_body(remaining_data, accounts)?)
}
SettlementInstruction::CreateOrder => {
ParsedInstruction::CreateOrder(CreateOrderInput::parse_body(remaining_data, accounts)?)
}
SettlementInstruction::CancelOrder => {
ParsedInstruction::CancelOrder(CancelOrderInput::parse_body(remaining_data, accounts)?)
}
SettlementInstruction::CreateSettlementOwnedOrder => {
ParsedInstruction::CreateSettlementOwnedOrder(
CreateSettlementOwnedOrderInput::parse_body(remaining_data, accounts)?,
)
}
SettlementInstruction::CreateBuffer => ParsedInstruction::CreateBuffer(
CreateBufferInput::parse_body(remaining_data, accounts)?,
),
SettlementInstruction::BeginSettle => {
ParsedInstruction::BeginSettle(BeginSettleInput::parse_body(remaining_data, accounts)?)
}
SettlementInstruction::FinalizeSettle => ParsedInstruction::FinalizeSettle(
FinalizeSettleInput::parse_body(remaining_data, accounts)?,
),
SettlementInstruction::ReclaimOrder => ParsedInstruction::ReclaimOrder(
ReclaimOrderInput::parse_body(remaining_data, accounts)?,
),
SettlementInstruction::ReclaimBuffer => ParsedInstruction::ReclaimBuffer(
ReclaimBufferInput::parse_body(remaining_data, accounts)?,
),
SettlementInstruction::TransferAuthority => ParsedInstruction::TransferAuthority(
TransferAuthorityInput::parse_body(remaining_data, accounts)?,
),
SettlementInstruction::AddSolver => {
ParsedInstruction::AddSolver(AddSolverInput::parse_body(remaining_data, accounts)?)
}
SettlementInstruction::RemoveSolver => ParsedInstruction::RemoveSolver(
RemoveSolverInput::parse_body(remaining_data, accounts)?,
),
SettlementInstruction::WithdrawNativeSol => ParsedInstruction::WithdrawNativeSol(
WithdrawNativeSolInput::parse_body(remaining_data, accounts)?,
),
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instruction::{
AddSolver, BeginSettle, CancelOrder, CreateBuffers, CreateOrder,
CreateSettlementOwnedOrder, FinalizeSettle, Initialize, InitializedIntent, RemoveSolver,
WithdrawNativeSol,
};
use cow_settlement_interface::{
data::intent::fixtures::sample_intent,
fixtures::pubkey_from_seed,
instruction::{
fixtures::fake_account_from_array, reclaim_buffer::ReclaimBuffer,
reclaim_order::ReclaimOrder, transfer_authority::TransferAuthority,
},
token_program::TokenProgram,
Instruction, Role,
};
fn build(instruction: SettlementInstruction) -> Instruction {
let program_id = pubkey_from_seed("program id");
let payer = pubkey_from_seed("payer");
let intent = sample_intent(Default::default());
match instruction {
SettlementInstruction::Initialize => Initialize {
program_id,
payer,
manager: payer,
solver_authority: payer,
reclaim_authority: payer,
settlement_owned_order_authority: payer,
}
.into(),
SettlementInstruction::CreateOrder => CreateOrder {
program_id,
owner: intent.owner,
created_by: payer,
intent: &intent,
}
.into(),
SettlementInstruction::CancelOrder => CancelOrder {
program_id,
owner: intent.owner,
created_by: payer,
intent: &intent,
}
.into(),
SettlementInstruction::CreateSettlementOwnedOrder => CreateSettlementOwnedOrder {
program_id,
authority: payer,
created_by: payer,
intent: &intent,
}
.into(),
SettlementInstruction::CreateBuffer => CreateBuffers {
program_id,
payer,
token_program: TokenProgram::SplToken,
mints: &[pubkey_from_seed("mint")],
}
.into(),
SettlementInstruction::BeginSettle => BeginSettle {
program_id,
solver: payer,
finalize_ix_index: 1,
auction_id: 42,
only_token_program: None,
orders: &[InitializedIntent {
intent: &intent,
pulls: &[],
use_transfer_checked: false,
}],
}
.into(),
SettlementInstruction::FinalizeSettle => FinalizeSettle {
program_id,
begin_ix_index: 0,
only_token_program: None,
orders: &[],
}
.into(),
SettlementInstruction::ReclaimOrder => ReclaimOrder {
program_id,
order_pda: pubkey_from_seed("order pda"),
reclaim_recipient: payer,
owner: None,
}
.instruction(),
SettlementInstruction::ReclaimBuffer => ReclaimBuffer {
program_id,
state_pda: pubkey_from_seed("state pda"),
reclaim_authority: payer,
reclaim_recipient: payer,
token_program: pubkey_from_seed("token program"),
buffers: &[(pubkey_from_seed("buffer pda"), pubkey_from_seed("mint"), 0)],
}
.into(),
SettlementInstruction::TransferAuthority => TransferAuthority {
program_id,
signer: payer,
state_pda: pubkey_from_seed("state pda"),
role: Role::Manager,
new_authority: payer,
}
.into(),
SettlementInstruction::AddSolver => AddSolver {
program_id,
authority: payer,
payer,
solver: pubkey_from_seed("solver"),
}
.into(),
SettlementInstruction::RemoveSolver => RemoveSolver {
program_id,
authority: payer,
rent_recipient: payer,
solver: pubkey_from_seed("solver"),
}
.into(),
SettlementInstruction::WithdrawNativeSol => WithdrawNativeSol {
program_id,
authority: payer,
recipient: payer,
amount: 42,
}
.into(),
}
}
#[test]
fn parses_every_instruction_to_its_variant() {
for expected in [
SettlementInstruction::Initialize,
SettlementInstruction::CreateOrder,
SettlementInstruction::CancelOrder,
SettlementInstruction::CreateSettlementOwnedOrder,
SettlementInstruction::CreateBuffer,
SettlementInstruction::BeginSettle,
SettlementInstruction::FinalizeSettle,
SettlementInstruction::ReclaimOrder,
SettlementInstruction::ReclaimBuffer,
SettlementInstruction::TransferAuthority,
SettlementInstruction::AddSolver,
SettlementInstruction::RemoveSolver,
SettlementInstruction::WithdrawNativeSol,
] {
let ix = build(expected);
let accounts: Vec<_> = ix
.accounts
.iter()
.map(|meta| fake_account_from_array(meta.pubkey.to_bytes()))
.collect();
let parsed = parse_instruction(&ix.data, &accounts)
.unwrap_or_else(|err| panic!("{expected:?} failed to parse: {err:?}"));
let actual = match parsed {
ParsedInstruction::Initialize(_) => SettlementInstruction::Initialize,
ParsedInstruction::CreateOrder(_) => SettlementInstruction::CreateOrder,
ParsedInstruction::CancelOrder(_) => SettlementInstruction::CancelOrder,
ParsedInstruction::CreateSettlementOwnedOrder(_) => {
SettlementInstruction::CreateSettlementOwnedOrder
}
ParsedInstruction::CreateBuffer(_) => SettlementInstruction::CreateBuffer,
ParsedInstruction::BeginSettle(_) => SettlementInstruction::BeginSettle,
ParsedInstruction::FinalizeSettle(_) => SettlementInstruction::FinalizeSettle,
ParsedInstruction::ReclaimOrder(_) => SettlementInstruction::ReclaimOrder,
ParsedInstruction::ReclaimBuffer(_) => SettlementInstruction::ReclaimBuffer,
ParsedInstruction::TransferAuthority(_) => SettlementInstruction::TransferAuthority,
ParsedInstruction::AddSolver(_) => SettlementInstruction::AddSolver,
ParsedInstruction::RemoveSolver(_) => SettlementInstruction::RemoveSolver,
ParsedInstruction::WithdrawNativeSol(_) => SettlementInstruction::WithdrawNativeSol,
};
assert_eq!(actual, expected);
}
}
}