use std::fmt;
use crate::error::CowError;
use super::{
gat::{GatOrder, decode_gat_static_input},
stop_loss::{STOP_LOSS_HANDLER_ADDRESS, StopLossOrder, decode_stop_loss_static_input},
twap::{TwapOrder, decode_twap_static_input},
types::{ConditionalOrderParams, TWAP_HANDLER_ADDRESS},
};
#[derive(Debug, Clone)]
pub enum ConditionalOrderKind {
Twap(TwapOrder),
StopLoss(StopLossOrder),
GoodAfterTime(GatOrder),
Unknown(ConditionalOrderParams),
}
impl ConditionalOrderKind {
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::Twap(_) => "twap",
Self::StopLoss(_) => "stop-loss",
Self::GoodAfterTime(_) => "good-after-time",
Self::Unknown(_) => "unknown",
}
}
#[must_use]
pub const fn is_twap(&self) -> bool {
matches!(self, Self::Twap(_))
}
#[must_use]
pub const fn is_stop_loss(&self) -> bool {
matches!(self, Self::StopLoss(_))
}
#[must_use]
pub const fn is_good_after_time(&self) -> bool {
matches!(self, Self::GoodAfterTime(_))
}
#[must_use]
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown(_))
}
}
impl fmt::Display for ConditionalOrderKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Twap(order) => write!(f, "twap({order})"),
Self::StopLoss(_) => f.write_str("stop-loss"),
Self::GoodAfterTime(_) => f.write_str("good-after-time"),
Self::Unknown(params) => write!(f, "unknown({:#x})", params.handler),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ConditionalOrderFactory;
impl ConditionalOrderFactory {
#[must_use]
pub const fn new() -> Self {
Self
}
pub fn from_params(
&self,
params: ConditionalOrderParams,
) -> Result<ConditionalOrderKind, CowError> {
if params.handler == TWAP_HANDLER_ADDRESS {
if params.static_input.len() == 14 * 32 {
let data = decode_gat_static_input(¶ms.static_input)?;
return Ok(ConditionalOrderKind::GoodAfterTime(GatOrder::with_salt(
data,
params.salt,
)));
}
let data = decode_twap_static_input(¶ms.static_input)?;
return Ok(ConditionalOrderKind::Twap(TwapOrder::with_salt(data, params.salt)));
}
if params.handler == STOP_LOSS_HANDLER_ADDRESS {
let data = decode_stop_loss_static_input(¶ms.static_input)?;
return Ok(ConditionalOrderKind::StopLoss(StopLossOrder::with_salt(data, params.salt)));
}
Ok(ConditionalOrderKind::Unknown(params))
}
}
impl fmt::Display for ConditionalOrderFactory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("conditional-order-factory")
}
}
#[cfg(test)]
mod tests {
use alloy_primitives::{Address, B256};
use super::*;
#[test]
fn factory_new() {
let factory = ConditionalOrderFactory::new();
assert_eq!(factory.to_string(), "conditional-order-factory");
}
#[test]
fn factory_unknown_handler() {
let factory = ConditionalOrderFactory::new();
let params = ConditionalOrderParams {
handler: Address::ZERO,
salt: B256::ZERO,
static_input: vec![],
};
let result = factory.from_params(params).unwrap();
assert!(result.is_unknown());
assert!(!result.is_twap());
assert!(!result.is_stop_loss());
assert!(!result.is_good_after_time());
assert_eq!(result.as_str(), "unknown");
}
#[test]
fn factory_twap_handler_empty_static_input_errors() {
let factory = ConditionalOrderFactory::new();
let params = ConditionalOrderParams {
handler: TWAP_HANDLER_ADDRESS,
salt: B256::ZERO,
static_input: vec![],
};
assert!(factory.from_params(params).is_err());
}
#[test]
fn factory_stop_loss_handler_empty_static_input_errors() {
let factory = ConditionalOrderFactory::new();
let params = ConditionalOrderParams {
handler: STOP_LOSS_HANDLER_ADDRESS,
salt: B256::ZERO,
static_input: vec![],
};
assert!(factory.from_params(params).is_err());
}
#[test]
fn conditional_order_kind_display_unknown() {
let kind = ConditionalOrderKind::Unknown(ConditionalOrderParams {
handler: Address::ZERO,
salt: B256::ZERO,
static_input: vec![],
});
let s = kind.to_string();
assert!(s.contains("unknown"));
}
#[test]
fn conditional_order_kind_display_stop_loss() {
let kind = ConditionalOrderKind::Unknown(ConditionalOrderParams {
handler: Address::ZERO,
salt: B256::ZERO,
static_input: vec![],
});
assert_eq!(kind.as_str(), "unknown");
}
}