//! Error types for Synor contracts. use alloc::string::String; use core::fmt; /// Result type for contract operations. pub type Result = core::result::Result; /// Contract error types. #[derive(Clone, Debug)] pub enum Error { /// Operation failed. Failed(String), /// Invalid method called. InvalidMethod, /// Invalid arguments provided. InvalidArgs(String), /// Insufficient balance. InsufficientBalance { required: u64, available: u64 }, /// Unauthorized operation. Unauthorized, /// Not found (storage key, etc.). NotFound(String), /// Already exists. AlreadyExists(String), /// Overflow in arithmetic operation. Overflow, /// Underflow in arithmetic operation. Underflow, /// Division by zero. DivisionByZero, /// Storage error. StorageError(String), /// Serialization/deserialization error. SerializationError(String), /// Cross-contract call failed. CallFailed(String), /// Contract is paused. Paused, /// Reentrancy detected. Reentrancy, /// Custom error with code. Custom { code: u32, message: String }, } impl Error { /// Creates a new failed error. pub fn failed(msg: impl Into) -> Self { Error::Failed(msg.into()) } /// Creates a new invalid args error. pub fn invalid_args(msg: impl Into) -> Self { Error::InvalidArgs(msg.into()) } /// Creates a new not found error. pub fn not_found(msg: impl Into) -> Self { Error::NotFound(msg.into()) } /// Creates a new already exists error. pub fn already_exists(msg: impl Into) -> Self { Error::AlreadyExists(msg.into()) } /// Creates a new storage error. pub fn storage(msg: impl Into) -> Self { Error::StorageError(msg.into()) } /// Creates a new serialization error. pub fn serialization(msg: impl Into) -> Self { Error::SerializationError(msg.into()) } /// Creates a new call failed error. pub fn call_failed(msg: impl Into) -> Self { Error::CallFailed(msg.into()) } /// Creates a custom error. pub fn custom(code: u32, msg: impl Into) -> Self { Error::Custom { code, message: msg.into(), } } /// Returns the error code. pub fn code(&self) -> u32 { match self { Error::Failed(_) => 1, Error::InvalidMethod => 2, Error::InvalidArgs(_) => 3, Error::InsufficientBalance { .. } => 4, Error::Unauthorized => 5, Error::NotFound(_) => 6, Error::AlreadyExists(_) => 7, Error::Overflow => 8, Error::Underflow => 9, Error::DivisionByZero => 10, Error::StorageError(_) => 11, Error::SerializationError(_) => 12, Error::CallFailed(_) => 13, Error::Paused => 14, Error::Reentrancy => 15, Error::Custom { code, .. } => *code, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Failed(msg) => write!(f, "Failed: {}", msg), Error::InvalidMethod => write!(f, "Invalid method"), Error::InvalidArgs(msg) => write!(f, "Invalid arguments: {}", msg), Error::InsufficientBalance { required, available, } => { write!( f, "Insufficient balance: required {}, available {}", required, available ) } Error::Unauthorized => write!(f, "Unauthorized"), Error::NotFound(msg) => write!(f, "Not found: {}", msg), Error::AlreadyExists(msg) => write!(f, "Already exists: {}", msg), Error::Overflow => write!(f, "Arithmetic overflow"), Error::Underflow => write!(f, "Arithmetic underflow"), Error::DivisionByZero => write!(f, "Division by zero"), Error::StorageError(msg) => write!(f, "Storage error: {}", msg), Error::SerializationError(msg) => write!(f, "Serialization error: {}", msg), Error::CallFailed(msg) => write!(f, "Call failed: {}", msg), Error::Paused => write!(f, "Contract is paused"), Error::Reentrancy => write!(f, "Reentrancy detected"), Error::Custom { code, message } => write!(f, "Error {}: {}", code, message), } } } /// Helper trait for converting Results to contract Results. pub trait IntoContractResult { /// Converts to a contract Result. fn into_contract_result(self) -> Result; } impl IntoContractResult for core::result::Result { fn into_contract_result(self) -> Result { self.map_err(|e| Error::failed(alloc::format!("{}", e))) } } /// Macro for creating custom errors. #[macro_export] macro_rules! contract_error { ($code:expr, $($arg:tt)*) => { $crate::Error::custom($code, alloc::format!($($arg)*)) }; } /// Macro for early return on error condition. #[macro_export] macro_rules! require { ($cond:expr, $err:expr) => { if !$cond { return Err($err); } }; ($cond:expr) => { if !$cond { return Err($crate::Error::failed("Requirement not met")); } }; } /// Macro for checking authorization. #[macro_export] macro_rules! require_auth { ($expected:expr) => { if $crate::context::caller() != $expected { return Err($crate::Error::Unauthorized); } }; }