use super::deferred_execution::{DeferredExecId, DeferredExecTarget};
use super::position::PositionId;
use crate::contracts::market::order::OrderId;
use crate::contracts::market::position::LiquidationReason;
use crate::prelude::*;
#[cw_serde]
pub enum CrankWorkInfo {
CloseAllPositions {
position: PositionId,
},
ResetLpBalances {},
Liquifunding {
position: PositionId,
},
Liquidation {
position: PositionId,
liquidation_reason: LiquidationReason,
},
DeferredExec {
deferred_exec_id: DeferredExecId,
target: DeferredExecTarget,
},
LimitOrder {
order_id: OrderId,
},
Completed {},
}
impl CrankWorkInfo {
pub fn receives_crank_rewards(&self) -> bool {
match self {
CrankWorkInfo::CloseAllPositions { .. }
| CrankWorkInfo::ResetLpBalances {}
| CrankWorkInfo::Completed { .. } => false,
CrankWorkInfo::Liquifunding { .. }
| CrankWorkInfo::Liquidation { .. }
| CrankWorkInfo::DeferredExec { .. }
| CrankWorkInfo::LimitOrder { .. } => true,
}
}
}
pub mod events {
use std::borrow::Cow;
use super::*;
use cosmwasm_std::Event;
pub struct CrankExecBatchEvent {
pub requested: u64,
pub paying: u64,
pub actual: Vec<(CrankWorkInfo, PricePoint)>,
}
impl From<CrankExecBatchEvent> for Event {
fn from(
CrankExecBatchEvent {
requested,
paying,
actual,
}: CrankExecBatchEvent,
) -> Self {
let mut event = Event::new("crank-batch-exec")
.add_attribute("requested", requested.to_string())
.add_attribute("actual", actual.len().to_string())
.add_attribute("paying", paying.to_string());
for (idx, (work, price_point)) in actual.into_iter().enumerate() {
event = event.add_attribute(
format!("work-{}", idx + 1),
match work {
CrankWorkInfo::CloseAllPositions { .. } => {
Cow::Borrowed("close-all-positions")
}
CrankWorkInfo::ResetLpBalances {} => "reset-lp-balances".into(),
CrankWorkInfo::Liquifunding { position, .. } => {
format!("liquifund {position}").into()
}
CrankWorkInfo::Liquidation { position, .. } => {
format!("liquidation {position}").into()
}
CrankWorkInfo::DeferredExec {
deferred_exec_id, ..
} => format!("deferred exec {deferred_exec_id}").into(),
CrankWorkInfo::LimitOrder { order_id, .. } => {
format!("limit order {order_id}").into()
}
CrankWorkInfo::Completed {} => {
format!("completed {}", price_point.timestamp).into()
}
},
)
}
event
}
}
pub struct CrankWorkInfoEvent {
pub work_info: CrankWorkInfo,
pub price_point: PricePoint,
}
impl From<CrankWorkInfoEvent> for Event {
fn from(
CrankWorkInfoEvent {
work_info,
price_point,
}: CrankWorkInfoEvent,
) -> Self {
let mut event = Event::new("crank-work")
.add_attribute(
"kind",
match work_info {
CrankWorkInfo::CloseAllPositions { .. } => "close-all-positions",
CrankWorkInfo::ResetLpBalances { .. } => "reset-lp-balances",
CrankWorkInfo::Completed { .. } => "completed",
CrankWorkInfo::Liquidation { .. } => "liquidation",
CrankWorkInfo::Liquifunding { .. } => "liquifunding",
CrankWorkInfo::DeferredExec { .. } => "deferred-exec",
CrankWorkInfo::LimitOrder { .. } => "limit-order",
},
)
.add_attribute("price-point-timestamp", price_point.timestamp.to_string())
.add_attribute("price-point", serde_json::to_string(&price_point).unwrap());
let (position_id, order_id) = match work_info {
CrankWorkInfo::CloseAllPositions { position } => (Some(position), None),
CrankWorkInfo::ResetLpBalances {} => (None, None),
CrankWorkInfo::Completed {} => (None, None),
CrankWorkInfo::Liquidation {
position,
liquidation_reason: _,
} => (Some(position), None),
CrankWorkInfo::Liquifunding { position } => (Some(position), None),
CrankWorkInfo::DeferredExec {
deferred_exec_id: _,
target,
} => (target.position_id(), target.order_id()),
CrankWorkInfo::LimitOrder { order_id } => (None, Some(order_id)),
};
if let Some(position_id) = position_id {
event = event.add_attribute("pos-id", position_id.to_string());
}
if let CrankWorkInfo::Liquidation {
liquidation_reason, ..
} = work_info
{
event = event.add_attribute("liquidation-reason", liquidation_reason.to_string());
}
if let CrankWorkInfo::DeferredExec {
deferred_exec_id,
target,
} = work_info
{
event = event
.add_attribute("deferred-exec-id", deferred_exec_id.to_string())
.add_attribute(
"deferred-exec-target",
match target {
DeferredExecTarget::DoesNotExist => "not-exist",
DeferredExecTarget::Position { .. } => "position",
DeferredExecTarget::Order { .. } => "order",
},
);
}
if let Some(order_id) = order_id {
event = event.add_attribute("order-id", order_id.to_string());
}
event
}
}
impl TryFrom<Event> for CrankWorkInfoEvent {
type Error = anyhow::Error;
fn try_from(evt: Event) -> anyhow::Result<Self> {
let get_position_id =
|| -> anyhow::Result<PositionId> { Ok(PositionId::new(evt.u64_attr("pos-id")?)) };
let get_order_id =
|| -> anyhow::Result<OrderId> { Ok(OrderId::new(evt.u64_attr("order-id")?)) };
let get_liquidation_reason = || -> anyhow::Result<LiquidationReason> {
match evt.string_attr("liquidation-reason")?.as_str() {
"liquidated" => Ok(LiquidationReason::Liquidated),
"take-profit" => Ok(LiquidationReason::TakeProfit),
_ => Err(PerpError::unimplemented().into()),
}
};
let work_info = evt.map_attr_result("kind", |s| match s {
"completed" => Ok(CrankWorkInfo::Completed {}),
"liquifunding" => Ok(CrankWorkInfo::Liquifunding {
position: get_position_id()?,
}),
"liquidation" => Ok(CrankWorkInfo::Liquidation {
position: get_position_id()?,
liquidation_reason: get_liquidation_reason()?,
}),
"limit-order" => Ok(CrankWorkInfo::LimitOrder {
order_id: get_order_id()?,
}),
"close-all-positions" => Ok(CrankWorkInfo::CloseAllPositions {
position: get_position_id()?,
}),
"reset-lp-balances" => Ok(CrankWorkInfo::ResetLpBalances {}),
"deferred-exec" => Ok(CrankWorkInfo::DeferredExec {
deferred_exec_id: DeferredExecId::from_u64(evt.u64_attr("deferred-exec-id")?),
target: evt.map_attr_result(
"deferred-exec-target",
|x| -> Result<DeferredExecTarget> {
match x {
"not-exist" => Ok(DeferredExecTarget::DoesNotExist),
"position" => get_position_id().map(DeferredExecTarget::Position),
"order" => get_order_id().map(DeferredExecTarget::Order),
_ => Err(PerpError::unimplemented().into()),
}
},
)?,
}),
_ => Err(PerpError::unimplemented().into()),
})?;
Ok(Self {
work_info,
price_point: evt.json_attr("price-point")?,
})
}
}
impl TryFrom<Event> for CrankWorkInfo {
type Error = anyhow::Error;
fn try_from(evt: Event) -> anyhow::Result<Self> {
CrankWorkInfoEvent::try_from(evt).map(|x| x.work_info)
}
}
}