synor/crates/synor-sdk/src/error.rs
2026-01-08 05:22:24 +05:30

203 lines
5.6 KiB
Rust

//! Error types for Synor contracts.
use alloc::string::String;
use core::fmt;
/// Result type for contract operations.
pub type Result<T> = core::result::Result<T, Error>;
/// 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<String>) -> Self {
Error::Failed(msg.into())
}
/// Creates a new invalid args error.
pub fn invalid_args(msg: impl Into<String>) -> Self {
Error::InvalidArgs(msg.into())
}
/// Creates a new not found error.
pub fn not_found(msg: impl Into<String>) -> Self {
Error::NotFound(msg.into())
}
/// Creates a new already exists error.
pub fn already_exists(msg: impl Into<String>) -> Self {
Error::AlreadyExists(msg.into())
}
/// Creates a new storage error.
pub fn storage(msg: impl Into<String>) -> Self {
Error::StorageError(msg.into())
}
/// Creates a new serialization error.
pub fn serialization(msg: impl Into<String>) -> Self {
Error::SerializationError(msg.into())
}
/// Creates a new call failed error.
pub fn call_failed(msg: impl Into<String>) -> Self {
Error::CallFailed(msg.into())
}
/// Creates a custom error.
pub fn custom(code: u32, msg: impl Into<String>) -> 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<T> {
/// Converts to a contract Result.
fn into_contract_result(self) -> Result<T>;
}
impl<T, E: fmt::Display> IntoContractResult<T> for core::result::Result<T, E> {
fn into_contract_result(self) -> Result<T> {
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);
}
};
}