use cow_settlement_interface::{
data::intent::OrderIntent,
pda::{order::find_order_pda, state::find_state_pda},
Instruction, Pubkey,
};
pub use cow_settlement_interface::instruction::settle::{Pull, TokenProgram};
pub struct InitializedIntent<'a> {
pub intent: &'a OrderIntent,
pub pulls: &'a [Pull],
}
pub struct BeginSettle<'a> {
pub program_id: Pubkey,
pub solver: Pubkey,
pub finalize_ix_index: u16,
pub auction_id: i64,
pub only_token_program: Option<TokenProgram>,
pub orders: &'a [InitializedIntent<'a>],
}
impl From<BeginSettle<'_>> for Instruction {
fn from(builder: BeginSettle<'_>) -> Self {
let mut order_pdas = Vec::with_capacity(builder.orders.len());
let mut sell_token_accounts = Vec::with_capacity(builder.orders.len());
let mut pull_lists: Vec<&[Pull]> = Vec::with_capacity(builder.orders.len());
for order in builder.orders {
let (order_pda, _bump) = find_order_pda(&builder.program_id, &order.intent.uid());
order_pdas.push(order_pda);
sell_token_accounts.push(order.intent.sell_token_account);
pull_lists.push(order.pulls);
}
let (state_pda, _bump) = find_state_pda(&builder.program_id);
cow_settlement_interface::instruction::settle::BeginSettle {
program_id: builder.program_id,
state_pda,
solver: builder.solver,
finalize_ix_index: builder.finalize_ix_index,
auction_id: builder.auction_id,
only_token_program: builder.only_token_program,
order_pdas: &order_pdas,
sell_token_accounts: &sell_token_accounts,
pulls: &pull_lists,
}
.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::proptest::{prelude::*, test_runner::TestCaseError};
use cow_settlement_interface::{
data::intent::fixtures::arb_order_intent,
fixtures::pubkey_from_seed,
instruction::{
fixtures::fake_account_from_array,
settle::{BeginSettleInput, INSTRUCTIONS_SYSVAR_ID},
InstructionInputParsing,
},
};
proptest! {
#[test]
fn begin_settle_derives_orders_from_intents(
finalize_ix_index in any::<u16>(),
intents in prop::collection::vec(arb_order_intent(), 1..=5),
) {
let program_id = pubkey_from_seed("program id");
let orders: Vec<InitializedIntent> = intents
.iter()
.map(|intent| InitializedIntent { intent, pulls: &[] })
.collect();
let ix = Instruction::from(BeginSettle {
program_id,
solver: pubkey_from_seed("solver"),
finalize_ix_index,
auction_id: 0,
only_token_program: None,
orders: &orders,
});
let mut expected: Vec<(Pubkey, Pubkey)> = intents
.iter()
.map(|intent| {
let (order_pda, _bump) = find_order_pda(&program_id, &intent.uid());
(order_pda, intent.sell_token_account)
})
.collect();
expected.sort_by_key(|(order_pda, _)| *order_pda);
let accounts: Vec<_> = ix
.accounts
.iter()
.map(|meta| fake_account_from_array(meta.pubkey.to_bytes()))
.collect();
let parsed = BeginSettleInput::parse(&ix.data, &accounts)
.map_err(|e| TestCaseError::fail(format!("parse failed: {e:?}")))?;
prop_assert_eq!(parsed.finalize_ix_index, finalize_ix_index);
prop_assert_eq!(
parsed.instructions_sysvar_account.address(),
&INSTRUCTIONS_SYSVAR_ID,
);
let actual: Vec<(Pubkey, Pubkey)> = parsed
.orders
.iter()
.map(|order| {
(
*order.order_pda.address(),
*order.sell_token_account.address(),
)
})
.collect();
prop_assert_eq!(actual, expected);
}
}
}