203 lines
5.6 KiB
Rust
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);
|
|
}
|
|
};
|
|
}
|