pub(crate) mod market;
use crate::event::CosmwasmEventExt;
use cosmwasm_std::Event;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct PerpError<T = ()> {
pub id: ErrorId,
pub domain: ErrorDomain,
pub description: String,
pub data: Option<T>,
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ErrorId {
InvalidStakeLp,
InvalidAmount,
SlippageAssert,
PriceAlreadyExists,
PriceNotFound,
PriceTooOld,
PositionUpdate,
NativeFunds,
Cw20Funds,
Auth,
Expired,
MsgValidation,
Conversion,
Config,
InternalReply,
Exceeded,
Any,
Stale,
InsufficientMargin,
InvalidLiquidityTokenMsg,
AddressAlreadyExists,
DeltaNeutralityFeeAlreadyLong,
DeltaNeutralityFeeAlreadyShort,
DeltaNeutralityFeeNewlyLong,
DeltaNeutralityFeeNewlyShort,
DeltaNeutralityFeeLongToShort,
DeltaNeutralityFeeShortToLong,
DirectionToBaseFlipped,
MissingFunds,
UnnecessaryFunds,
NoYieldToClaim,
InsufficientForReinvest,
TimestampSubtractUnderflow,
InvalidInfiniteMaxGains,
InvalidInfiniteTakeProfitPrice,
MaxGainsTooLarge,
WithdrawTooMuch,
InsufficientLiquidityForWithdrawal,
MissingPosition,
TraderLeverageOutOfRange,
CounterLeverageOutOfRange,
MinimumDeposit,
Congestion,
MaxLiquidity,
InvalidTriggerPrice,
LiquidityCooldown,
PendingDeferredExec,
VolatilePriceFeedTimeDelta,
LimitOrderAlreadyCanceling,
PositionAlreadyClosing,
NoPricePublishTimeFound,
PositionAlreadyClosed,
MissingTakeProfit,
InsufficientLiquidityForUnlock,
Liquidity,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[allow(missing_docs)]
pub enum ErrorDomain {
Market,
SpotPrice,
PositionToken,
LiquidityToken,
Cw20,
Wallet,
Factory,
Default,
Faucet,
Pyth,
Farming,
Stride,
SimpleOracle,
}
impl<T: Serialize> fmt::Display for PerpError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
serde_json::to_string_pretty(&self).map_err(|_| fmt::Error)?
)
}
}
impl<T: Serialize> fmt::Debug for PerpError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
serde_json::to_string_pretty(&self).map_err(|_| fmt::Error)?
)
}
}
impl PerpError {
pub fn new(id: ErrorId, domain: ErrorDomain, desc: impl Into<String>) -> Self {
PerpError {
id,
domain,
description: desc.into(),
data: None,
}
}
pub fn auth(domain: ErrorDomain, desc: impl Into<String>) -> Self {
PerpError {
id: ErrorId::Auth,
domain,
description: desc.into(),
data: None,
}
}
pub fn market(id: ErrorId, desc: impl Into<String>) -> Self {
PerpError {
id,
domain: ErrorDomain::Market,
description: desc.into(),
data: None,
}
}
pub fn cw20(id: ErrorId, desc: impl Into<String>) -> Self {
PerpError {
id,
domain: ErrorDomain::Cw20,
description: desc.into(),
data: None,
}
}
pub fn mixin_event(&self, evt: Event) -> Event {
let evt = evt.add_attributes([
("error-id", serde_json::to_string(&self.id).unwrap()),
("error-domain", serde_json::to_string(&self.domain).unwrap()),
("error-description", self.description.to_string()),
]);
match &self.data {
None => evt,
Some(data) => evt.add_attribute("error-data", serde_json::to_string(data).unwrap()),
}
}
pub fn unimplemented() -> Self {
Self {
id: ErrorId::Any,
domain: ErrorDomain::Default,
description: "unimplemented".to_string(),
data: None,
}
}
}
impl TryFrom<Event> for PerpError {
type Error = anyhow::Error;
fn try_from(evt: Event) -> anyhow::Result<Self> {
Ok(Self {
id: evt.json_attr("error-id")?,
domain: evt.json_attr("error-domain")?,
description: evt.string_attr("error-description")?,
data: evt.try_json_attr("error-data")?,
})
}
}
impl<T: Serialize> std::error::Error for PerpError<T> {}