use sui_sdk_types::Address;
#[derive(thiserror::Error, Debug, Clone)]
#[non_exhaustive]
pub enum Error {
#[error("Conversion error due to input issue: {0}")]
Input(String),
#[error("Gas object should be an immutable or owned object")]
WrongGasObject,
#[error("Missing object id")]
MissingObjectId,
#[error("Missing version for object {0}")]
MissingVersion(Address),
#[error("Missing digest for object {0}")]
MissingDigest(Address),
#[error("Missing sender")]
MissingSender,
#[error("Missing gas objects")]
MissingGasObjects,
#[error("Missing gas budget")]
MissingGasBudget,
#[error("Missing gas price")]
MissingGasPrice,
#[error("Missing object kind for object {0}")]
MissingObjectKind(Address),
#[error("Unknown shared object mutability for object {0}")]
SharedObjectMutability(Address),
#[error("{0}")]
#[cfg(feature = "intents")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "intents")))]
SimulationFailure(Box<SimulationFailure>),
}
#[derive(Debug, Clone)]
#[cfg(feature = "intents")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "intents")))]
pub struct SimulationFailure {
error: sui_rpc::proto::sui::rpc::v2::ExecutionError,
}
#[cfg(feature = "intents")]
impl SimulationFailure {
pub(crate) fn new(error: sui_rpc::proto::sui::rpc::v2::ExecutionError) -> Self {
Self { error }
}
pub fn execution_error(&self) -> &sui_rpc::proto::sui::rpc::v2::ExecutionError {
&self.error
}
pub fn description(&self) -> Option<&str> {
self.error.description_opt()
}
pub fn command(&self) -> Option<u64> {
self.error.command_opt()
}
pub fn kind(
&self,
) -> Option<sui_rpc::proto::sui::rpc::v2::execution_error::ExecutionErrorKind> {
self.error.kind.and_then(|k| {
sui_rpc::proto::sui::rpc::v2::execution_error::ExecutionErrorKind::try_from(k).ok()
})
}
pub fn move_abort(&self) -> Option<&sui_rpc::proto::sui::rpc::v2::MoveAbort> {
self.error.abort_opt()
}
pub fn clever_error(&self) -> Option<&sui_rpc::proto::sui::rpc::v2::CleverError> {
self.error.abort_opt()?.clever_error.as_ref()
}
}
#[cfg(feature = "intents")]
impl std::fmt::Display for SimulationFailure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "transaction simulation failed")?;
if let Some(cmd) = self.command() {
write!(f, " in command {cmd}")?;
}
if let Some(kind) = self.kind() {
write!(f, " ({})", kind.as_str_name())?;
}
if let Some(desc) = self.description()
&& !desc.is_empty()
{
write!(f, ": {desc}")?;
}
if let Some(abort) = self.move_abort() {
if let Some(loc) = &abort.location
&& let (Some(pkg), Some(module)) = (loc.package.as_deref(), loc.module.as_deref())
{
write!(f, " at {pkg}::{module}")?;
if let Some(func) = loc.function_name.as_deref() {
write!(f, "::{func}")?;
}
}
if let Some(clever) = &abort.clever_error
&& let Some(name) = clever.constant_name.as_deref()
{
write!(f, " [{name}")?;
if let Some(sui_rpc::proto::sui::rpc::v2::clever_error::Value::Rendered(v)) =
&clever.value
{
write!(f, " = {v}")?;
}
write!(f, "]")?;
}
}
Ok(())
}
}