1pub(crate) mod market;
3
4use crate::event::CosmwasmEventExt;
5use cosmwasm_std::Event;
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
12pub struct PerpError<T = ()> {
13 pub id: ErrorId,
15 pub domain: ErrorDomain,
17 pub description: String,
19 pub data: Option<T>,
21}
22
23#[allow(missing_docs)]
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
26#[serde(rename_all = "snake_case")]
27pub enum ErrorId {
28 InvalidStakeLp,
29 InvalidAmount,
30 SlippageAssert,
31 PriceAlreadyExists,
32 PriceNotFound,
33 PriceTooOld,
34 PositionUpdate,
35 NativeFunds,
36 Cw20Funds,
37 Auth,
38 Expired,
39 MsgValidation,
40 Conversion,
41 Config,
42 InternalReply,
43 Exceeded,
44 Any,
45 Stale,
46 InsufficientMargin,
47 InvalidLiquidityTokenMsg,
48 AddressAlreadyExists,
49 DeltaNeutralityFeeAlreadyLong,
50 DeltaNeutralityFeeAlreadyShort,
51 DeltaNeutralityFeeNewlyLong,
52 DeltaNeutralityFeeNewlyShort,
53 DeltaNeutralityFeeLongToShort,
54 DeltaNeutralityFeeShortToLong,
55 DirectionToBaseFlipped,
56 MissingFunds,
57 UnnecessaryFunds,
58 NoYieldToClaim,
59 InsufficientForReinvest,
60 TimestampSubtractUnderflow,
61
62 InvalidInfiniteMaxGains,
64 InvalidInfiniteTakeProfitPrice,
65 MaxGainsTooLarge,
66 WithdrawTooMuch,
67 InsufficientLiquidityForWithdrawal,
68 MissingPosition,
69 TraderLeverageOutOfRange,
70 MinimumDeposit,
71 Congestion,
72 MaxLiquidity,
73 InvalidTriggerPrice,
74 LiquidityCooldown,
75 PendingDeferredExec,
76 VolatilePriceFeedTimeDelta,
77 LimitOrderAlreadyCanceling,
78 PositionAlreadyClosing,
79 NoPricePublishTimeFound,
80 PositionAlreadyClosed,
81 MissingTakeProfit,
82 InsufficientLiquidityForUnlock,
83 Liquidity,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
88#[serde(rename_all = "snake_case")]
89#[allow(missing_docs)]
90pub enum ErrorDomain {
91 Market,
92 SpotPrice,
93 PositionToken,
94 LiquidityToken,
95 Cw20,
96 Wallet,
97 Factory,
98 Default,
99 Faucet,
100 Pyth,
101 Farming,
102 Stride,
103 SimpleOracle,
104}
105
106impl<T: Serialize> fmt::Display for PerpError<T> {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 write!(
109 f,
110 "{}",
111 serde_json::to_string_pretty(&self).map_err(|_| fmt::Error)?
112 )
113 }
114}
115
116impl<T: Serialize> fmt::Debug for PerpError<T> {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 write!(
119 f,
120 "{}",
121 serde_json::to_string_pretty(&self).map_err(|_| fmt::Error)?
122 )
123 }
124}
125
126impl PerpError {
127 pub fn new(id: ErrorId, domain: ErrorDomain, desc: impl Into<String>) -> Self {
129 PerpError {
130 id,
131 domain,
132 description: desc.into(),
133 data: None,
134 }
135 }
136
137 pub fn auth(domain: ErrorDomain, desc: impl Into<String>) -> Self {
139 PerpError {
140 id: ErrorId::Auth,
141 domain,
142 description: desc.into(),
143 data: None,
144 }
145 }
146
147 pub fn market(id: ErrorId, desc: impl Into<String>) -> Self {
149 PerpError {
150 id,
151 domain: ErrorDomain::Market,
152 description: desc.into(),
153 data: None,
154 }
155 }
156
157 pub fn cw20(id: ErrorId, desc: impl Into<String>) -> Self {
159 PerpError {
160 id,
161 domain: ErrorDomain::Cw20,
162 description: desc.into(),
163 data: None,
164 }
165 }
166 pub fn mixin_event(&self, evt: Event) -> Event {
168 let evt = evt.add_attributes([
170 ("error-id", serde_json::to_string(&self.id).unwrap()),
171 ("error-domain", serde_json::to_string(&self.domain).unwrap()),
172 ("error-description", self.description.to_string()),
173 ]);
174
175 match &self.data {
176 None => evt,
177 Some(data) => evt.add_attribute("error-data", serde_json::to_string(data).unwrap()),
179 }
180 }
181
182 pub fn unimplemented() -> Self {
184 Self {
185 id: ErrorId::Any,
186 domain: ErrorDomain::Default,
187 description: "unimplemented".to_string(),
188 data: None,
189 }
190 }
191}
192
193impl TryFrom<Event> for PerpError {
194 type Error = anyhow::Error;
195
196 fn try_from(evt: Event) -> anyhow::Result<Self> {
197 Ok(Self {
198 id: evt.json_attr("error-id")?,
199 domain: evt.json_attr("error-domain")?,
200 description: evt.string_attr("error-description")?,
201 data: evt.try_json_attr("error-data")?,
202 })
203 }
204}
205
206impl<T: Serialize> std::error::Error for PerpError<T> {}