2022-01-21 10:21:46 -08:00
|
|
|
use anchor_lang::prelude::*;
|
2022-07-07 07:55:04 -07:00
|
|
|
use core::fmt::Display;
|
2022-01-21 10:21:46 -08:00
|
|
|
|
2022-02-28 01:36:31 -08:00
|
|
|
// todo: group error blocks by kind
|
|
|
|
// todo: add comments which indicate decimal code for an error
|
2022-02-22 00:10:44 -08:00
|
|
|
#[error_code]
|
|
|
|
pub enum MangoError {
|
2022-01-21 10:21:46 -08:00
|
|
|
#[msg("")]
|
|
|
|
SomeError,
|
2022-08-01 07:53:30 -07:00
|
|
|
#[msg("")]
|
|
|
|
NotImplementedError,
|
2022-07-07 07:55:04 -07:00
|
|
|
#[msg("checked math error")]
|
2022-03-11 00:57:30 -08:00
|
|
|
MathError,
|
|
|
|
#[msg("")]
|
2022-02-28 21:28:12 -08:00
|
|
|
UnexpectedOracle,
|
2022-07-07 07:55:04 -07:00
|
|
|
#[msg("oracle type cannot be determined")]
|
2022-02-28 21:28:12 -08:00
|
|
|
UnknownOracleType,
|
2022-03-02 21:15:28 -08:00
|
|
|
#[msg("")]
|
2022-06-23 01:19:33 -07:00
|
|
|
InvalidFlashLoanTargetCpiProgram,
|
2022-07-07 07:55:04 -07:00
|
|
|
#[msg("health must be positive")]
|
2022-03-03 04:10:20 -08:00
|
|
|
HealthMustBePositive,
|
2022-08-24 07:07:22 -07:00
|
|
|
#[msg("health must be positive or increase")]
|
|
|
|
HealthMustBePositiveOrIncrease,
|
2022-07-19 05:56:26 -07:00
|
|
|
#[msg("health must be negative")]
|
|
|
|
HealthMustBeNegative,
|
2022-07-07 07:55:04 -07:00
|
|
|
#[msg("the account is bankrupt")]
|
2022-03-30 01:00:52 -07:00
|
|
|
IsBankrupt,
|
2022-07-07 07:55:04 -07:00
|
|
|
#[msg("the account is not bankrupt")]
|
|
|
|
IsNotBankrupt,
|
|
|
|
#[msg("no free token position index")]
|
|
|
|
NoFreeTokenPositionIndex,
|
|
|
|
#[msg("no free serum3 open orders index")]
|
|
|
|
NoFreeSerum3OpenOrdersIndex,
|
|
|
|
#[msg("no free perp position index")]
|
|
|
|
NoFreePerpPositionIndex,
|
|
|
|
#[msg("serum3 open orders exist already")]
|
|
|
|
Serum3OpenOrdersExistAlready,
|
2022-07-19 02:36:23 -07:00
|
|
|
#[msg("bank vault has insufficent funds")]
|
|
|
|
InsufficentBankVaultFunds,
|
2022-08-22 02:02:01 -07:00
|
|
|
#[msg("account is currently being liquidated")]
|
|
|
|
BeingLiquidated,
|
2022-09-01 09:07:57 -07:00
|
|
|
#[msg("invalid bank")]
|
|
|
|
InvalidBank,
|
|
|
|
#[msg("account profitability is mismatched")]
|
|
|
|
ProfitabilityMismatch,
|
|
|
|
#[msg("cannot settle with self")]
|
|
|
|
CannotSettleWithSelf,
|
|
|
|
#[msg("perp position does not exist")]
|
|
|
|
PerpPositionDoesNotExist,
|
|
|
|
#[msg("max settle amount must be greater than zero")]
|
|
|
|
MaxSettleAmountMustBeGreaterThanZero,
|
2022-09-07 07:10:49 -07:00
|
|
|
#[msg("the perp position has open orders or unprocessed fill events")]
|
|
|
|
HasOpenPerpOrders,
|
2022-11-10 06:47:11 -08:00
|
|
|
#[msg("an oracle does not reach the confidence threshold")]
|
|
|
|
OracleConfidence,
|
|
|
|
#[msg("an oracle is stale")]
|
|
|
|
OracleStale,
|
2022-11-17 23:58:56 -08:00
|
|
|
#[msg("settlement amount must always be positive")]
|
|
|
|
SettlementAmountMustBePositive,
|
2022-11-25 04:45:17 -08:00
|
|
|
#[msg("bank utilization has reached limit")]
|
|
|
|
BankBorrowLimitReached,
|
|
|
|
#[msg("bank net borrows has reached limit - this is an intermittent error - the limit will reset regularly")]
|
|
|
|
BankNetBorrowsLimitReached,
|
2022-12-06 00:25:24 -08:00
|
|
|
#[msg("token position does not exist")]
|
|
|
|
TokenPositionDoesNotExist,
|
2022-12-20 02:24:19 -08:00
|
|
|
#[msg("token deposits into accounts that are being liquidated must bring their health above the init threshold")]
|
|
|
|
DepositsIntoLiquidatingMustRecover,
|
2023-01-04 00:24:40 -08:00
|
|
|
#[msg("token is in reduce only mode")]
|
|
|
|
TokenInReduceOnlyMode,
|
|
|
|
#[msg("market is in reduce only mode")]
|
|
|
|
MarketInReduceOnlyMode,
|
2023-01-12 00:12:55 -08:00
|
|
|
#[msg("group is halted")]
|
|
|
|
GroupIsHalted,
|
2023-01-12 00:07:13 -08:00
|
|
|
#[msg("the perp position has non-zero base lots")]
|
|
|
|
PerpHasBaseLots,
|
|
|
|
#[msg("there are open or unsettled serum3 orders")]
|
|
|
|
HasOpenOrUnsettledSerum3Orders,
|
|
|
|
#[msg("has liquidatable token position")]
|
|
|
|
HasLiquidatableTokenPosition,
|
|
|
|
#[msg("has liquidatable perp base position")]
|
|
|
|
HasLiquidatablePerpBasePosition,
|
|
|
|
#[msg("has liquidatable trusted perp pnl")]
|
|
|
|
HasLiquidatableTrustedPerpPnl,
|
2023-01-12 04:08:10 -08:00
|
|
|
#[msg("account is frozen")]
|
|
|
|
AccountIsFrozen,
|
2023-01-23 06:02:48 -08:00
|
|
|
#[msg("Init Asset Weight can't be negative")]
|
|
|
|
InitAssetWeightCantBeNegative,
|
2023-01-23 01:45:45 -08:00
|
|
|
#[msg("has open perp taker fills")]
|
|
|
|
HasOpenPerpTakerFills,
|
2023-01-23 05:58:03 -08:00
|
|
|
#[msg("deposit crosses the current group deposit limit")]
|
|
|
|
DepositLimit,
|
2022-12-06 00:25:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MangoError {
|
|
|
|
pub fn error_code(&self) -> u32 {
|
|
|
|
(*self).into()
|
|
|
|
}
|
2022-07-07 07:55:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Contextable {
|
|
|
|
/// Add a context string `c` to a Result or Error
|
|
|
|
///
|
|
|
|
/// Example: foo().context("calling foo")?;
|
|
|
|
fn context(self, c: impl Display) -> Self;
|
|
|
|
|
|
|
|
/// Like `context()`, but evaluate the context string lazily
|
|
|
|
///
|
|
|
|
/// Use this if it's expensive to generate, like a format!() call.
|
|
|
|
fn with_context<C, F>(self, c: F) -> Self
|
|
|
|
where
|
|
|
|
C: Display,
|
|
|
|
F: FnOnce() -> C;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Contextable for Error {
|
|
|
|
fn context(self, c: impl Display) -> Self {
|
|
|
|
match self {
|
|
|
|
Error::AnchorError(err) => Error::AnchorError(AnchorError {
|
|
|
|
error_msg: if err.error_msg.is_empty() {
|
|
|
|
format!("{}", c)
|
|
|
|
} else {
|
|
|
|
format!("{}; {}", err.error_msg, c)
|
|
|
|
},
|
|
|
|
..err
|
|
|
|
}),
|
|
|
|
// Maybe wrap somehow?
|
|
|
|
Error::ProgramError(err) => Error::ProgramError(err),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn with_context<C, F>(self, c: F) -> Self
|
|
|
|
where
|
|
|
|
C: Display,
|
|
|
|
F: FnOnce() -> C,
|
|
|
|
{
|
|
|
|
self.context(c())
|
|
|
|
}
|
2022-01-21 10:21:46 -08:00
|
|
|
}
|
2022-07-07 07:55:04 -07:00
|
|
|
|
|
|
|
impl<T> Contextable for Result<T> {
|
|
|
|
fn context(self, c: impl Display) -> Self {
|
|
|
|
if let Err(err) = self {
|
|
|
|
Err(err.context(c))
|
|
|
|
} else {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn with_context<C, F>(self, c: F) -> Self
|
|
|
|
where
|
|
|
|
C: Display,
|
|
|
|
F: FnOnce() -> C,
|
|
|
|
{
|
|
|
|
if let Err(err) = self {
|
|
|
|
Err(err.context(c()))
|
|
|
|
} else {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates an Error with a particular message, using format!() style arguments
|
|
|
|
///
|
|
|
|
/// Example: error_msg!("index {} not found", index)
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! error_msg {
|
|
|
|
($($arg:tt)*) => {
|
|
|
|
error!(MangoError::SomeError).context(format!($($arg)*))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:25:24 -08:00
|
|
|
/// Creates an Error with a particular message, using format!() style arguments
|
|
|
|
///
|
2023-01-11 05:32:15 -08:00
|
|
|
/// Example: error_msg_typed!(TokenPositionMissing, "index {} not found", index)
|
2022-12-06 00:25:24 -08:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! error_msg_typed {
|
2023-01-11 05:32:15 -08:00
|
|
|
($code:expr, $($arg:tt)*) => {
|
|
|
|
error!($code).context(format!($($arg)*))
|
2022-12-06 00:25:24 -08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-07-07 07:55:04 -07:00
|
|
|
/// Like anchor's require!(), but with a customizable message
|
|
|
|
///
|
2023-01-11 05:32:15 -08:00
|
|
|
/// Example: require_msg!(condition, "the condition on account {} was violated", account_key);
|
2022-07-07 07:55:04 -07:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! require_msg {
|
|
|
|
($invariant:expr, $($arg:tt)*) => {
|
|
|
|
if !($invariant) {
|
2022-08-02 00:04:02 -07:00
|
|
|
return Err(error_msg!($($arg)*));
|
2022-07-07 07:55:04 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-11 05:32:15 -08:00
|
|
|
/// Like anchor's require!(), but with a customizable message and type
|
|
|
|
///
|
|
|
|
/// Example: require_msg_typed!(condition, "the condition on account {} was violated", account_key);
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! require_msg_typed {
|
|
|
|
($invariant:expr, $code:expr, $($arg:tt)*) => {
|
|
|
|
if !($invariant) {
|
|
|
|
return Err(error_msg_typed!($code, $($arg)*));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-07-07 07:55:04 -07:00
|
|
|
pub use error_msg;
|
2022-12-06 00:25:24 -08:00
|
|
|
pub use error_msg_typed;
|
2022-07-07 07:55:04 -07:00
|
|
|
pub use require_msg;
|
2023-01-11 05:32:15 -08:00
|
|
|
pub use require_msg_typed;
|