contract_extrinsics/
error.rs1use sp_runtime::DispatchError;
18use std::fmt::{
19 self,
20 Debug,
21 Display,
22};
23
24#[derive(serde::Serialize)]
25pub enum ErrorVariant {
26 #[serde(rename = "module_error")]
27 Module(ModuleError),
28 #[serde(rename = "generic_error")]
29 Generic(GenericError),
30}
31
32impl From<subxt::Error> for ErrorVariant {
33 fn from(error: subxt::Error) -> Self {
34 match error {
35 subxt::Error::Runtime(subxt::error::DispatchError::Module(module_err)) => {
36 module_err
37 .details()
38 .map(|details| {
39 ErrorVariant::Module(ModuleError {
40 pallet: details.pallet.name().to_string(),
41 error: details.variant.name.to_string(),
42 docs: details.variant.docs.clone(),
43 })
44 })
45 .unwrap_or_else(|err| {
46 ErrorVariant::Generic(GenericError::from_message(format!(
47 "Error extracting subxt error details: {}",
48 err
49 )))
50 })
51 }
52 err => ErrorVariant::Generic(GenericError::from_message(err.to_string())),
53 }
54 }
55}
56
57impl From<anyhow::Error> for ErrorVariant {
58 fn from(error: anyhow::Error) -> Self {
59 Self::Generic(GenericError::from_message(format!("{error:?}")))
60 }
61}
62
63impl From<&str> for ErrorVariant {
64 fn from(err: &str) -> Self {
65 Self::Generic(GenericError::from_message(err.to_owned()))
66 }
67}
68
69impl From<std::io::Error> for ErrorVariant {
70 fn from(value: std::io::Error) -> Self {
71 Self::Generic(GenericError::from_message(value.to_string()))
72 }
73}
74
75impl From<serde_json::Error> for ErrorVariant {
76 fn from(error: serde_json::Error) -> Self {
77 Self::Generic(GenericError::from_message(format!("{error:?}")))
78 }
79}
80
81#[derive(serde::Serialize)]
82pub struct ModuleError {
83 pub pallet: String,
84 pub error: String,
85 pub docs: Vec<String>,
86}
87
88#[derive(serde::Serialize)]
89pub struct GenericError {
90 error: String,
91}
92
93impl GenericError {
94 pub fn from_message(error: String) -> Self {
95 GenericError { error }
96 }
97}
98
99impl ErrorVariant {
100 pub fn from_dispatch_error(
101 error: &DispatchError,
102 metadata: &subxt::Metadata,
103 ) -> anyhow::Result<ErrorVariant> {
104 match error {
105 DispatchError::Module(err) => {
106 let pallet = metadata.pallet_by_index_err(err.index)?;
107 let variant =
108 pallet.error_variant_by_index(err.error[0]).ok_or_else(|| {
109 anyhow::anyhow!("Error variant {} not found", err.error[0])
110 })?;
111 Ok(ErrorVariant::Module(ModuleError {
112 pallet: pallet.name().to_string(),
113 error: variant.name.to_owned(),
114 docs: variant.docs.to_owned(),
115 }))
116 }
117 err => {
118 Ok(ErrorVariant::Generic(GenericError::from_message(format!(
119 "DispatchError: {err:?}"
120 ))))
121 }
122 }
123 }
124}
125
126impl Debug for ErrorVariant {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 <Self as Display>::fmt(self, f)
129 }
130}
131
132impl Display for ErrorVariant {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 match self {
135 ErrorVariant::Module(err) => {
136 f.write_fmt(format_args!(
137 "ModuleError: {}::{}: {:?}",
138 err.pallet, err.error, err.docs
139 ))
140 }
141 ErrorVariant::Generic(err) => write!(f, "{}", err.error),
142 }
143 }
144}