1use crate::{alloc::string::ToString, Error, Panic, Result, Revert, SolError};
2use alloc::{string::String, vec::Vec};
3use core::{convert::Infallible, fmt, iter::FusedIterator, marker::PhantomData};
4
5mod event;
6pub use event::SolEventInterface;
7
8pub trait SolInterface: Sized {
26 const NAME: &'static str;
28
29 const MIN_DATA_LENGTH: usize;
33
34 const COUNT: usize;
36
37 fn selector(&self) -> [u8; 4];
39
40 fn selector_at(i: usize) -> Option<[u8; 4]>;
46
47 fn valid_selector(selector: [u8; 4]) -> bool;
49
50 fn type_check(selector: [u8; 4]) -> Result<()> {
52 if Self::valid_selector(selector) {
53 Ok(())
54 } else {
55 Err(Error::UnknownSelector { name: Self::NAME, selector: selector.into() })
56 }
57 }
58
59 fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> Result<Self>;
61
62 fn abi_decode_raw_validate(selector: [u8; 4], data: &[u8]) -> Result<Self>;
67
68 fn abi_encoded_size(&self) -> usize;
70
71 fn abi_encode_raw(&self, out: &mut Vec<u8>);
73
74 #[inline]
76 fn selectors() -> Selectors<Self> {
77 Selectors::new()
78 }
79
80 #[inline]
82 fn abi_encode(&self) -> Vec<u8> {
83 let mut out = Vec::with_capacity(4 + self.abi_encoded_size());
84 out.extend(self.selector());
85 self.abi_encode_raw(&mut out);
86 out
87 }
88
89 #[inline]
91 fn abi_decode(data: &[u8]) -> Result<Self> {
92 if data.len() < Self::MIN_DATA_LENGTH.saturating_add(4) {
93 Err(crate::Error::type_check_fail(data, Self::NAME))
94 } else {
95 let (selector, data) = data.split_first_chunk().unwrap();
96 Self::abi_decode_raw(*selector, data)
97 }
98 }
99
100 #[inline]
105 fn abi_decode_validate(data: &[u8]) -> Result<Self> {
106 if data.len() < Self::MIN_DATA_LENGTH.saturating_add(4) {
107 Err(crate::Error::type_check_fail(data, Self::NAME))
108 } else {
109 let (selector, data) = data.split_first_chunk().unwrap();
110 Self::abi_decode_raw_validate(*selector, data)
111 }
112 }
113}
114
115impl SolInterface for Infallible {
117 const NAME: &'static str = "GenericContractError";
119
120 const MIN_DATA_LENGTH: usize = usize::MAX;
122 const COUNT: usize = 0;
123
124 #[inline]
125 fn selector(&self) -> [u8; 4] {
126 unreachable!()
127 }
128
129 #[inline]
130 fn selector_at(_i: usize) -> Option<[u8; 4]> {
131 None
132 }
133
134 #[inline]
135 fn valid_selector(_selector: [u8; 4]) -> bool {
136 false
137 }
138
139 #[inline]
140 fn abi_decode_raw(selector: [u8; 4], _data: &[u8]) -> Result<Self> {
141 Self::type_check(selector).map(|()| unreachable!())
142 }
143
144 #[inline]
145 fn abi_decode_raw_validate(selector: [u8; 4], _data: &[u8]) -> Result<Self> {
146 Self::type_check(selector).map(|()| unreachable!())
147 }
148
149 #[inline]
150 fn abi_encoded_size(&self) -> usize {
151 unreachable!()
152 }
153
154 #[inline]
155 fn abi_encode_raw(&self, _out: &mut Vec<u8>) {
156 unreachable!()
157 }
158}
159
160pub type GenericContractError = ContractError<Infallible>;
164
165#[derive(Clone, Debug, PartialEq, Eq)]
172pub enum ContractError<T> {
173 CustomError(T),
175 Revert(Revert),
177 Panic(Panic),
179}
180
181impl<T: SolInterface> From<T> for ContractError<T> {
182 #[inline]
183 fn from(value: T) -> Self {
184 Self::CustomError(value)
185 }
186}
187
188impl<T> From<Revert> for ContractError<T> {
189 #[inline]
190 fn from(value: Revert) -> Self {
191 Self::Revert(value)
192 }
193}
194
195impl<T> TryFrom<ContractError<T>> for Revert {
196 type Error = ContractError<T>;
197
198 #[inline]
199 fn try_from(value: ContractError<T>) -> Result<Self, Self::Error> {
200 match value {
201 ContractError::Revert(inner) => Ok(inner),
202 _ => Err(value),
203 }
204 }
205}
206
207impl<T> From<Panic> for ContractError<T> {
208 #[inline]
209 fn from(value: Panic) -> Self {
210 Self::Panic(value)
211 }
212}
213
214impl<T> TryFrom<ContractError<T>> for Panic {
215 type Error = ContractError<T>;
216
217 #[inline]
218 fn try_from(value: ContractError<T>) -> Result<Self, Self::Error> {
219 match value {
220 ContractError::Panic(inner) => Ok(inner),
221 _ => Err(value),
222 }
223 }
224}
225
226impl<T: fmt::Display> fmt::Display for ContractError<T> {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 match self {
229 Self::CustomError(error) => error.fmt(f),
230 Self::Panic(panic) => panic.fmt(f),
231 Self::Revert(revert) => revert.fmt(f),
232 }
233 }
234}
235
236impl<T: core::error::Error + 'static> core::error::Error for ContractError<T> {
237 #[inline]
238 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
239 match self {
240 Self::CustomError(error) => Some(error),
241 Self::Panic(panic) => Some(panic),
242 Self::Revert(revert) => Some(revert),
243 }
244 }
245}
246
247impl<T: SolInterface> SolInterface for ContractError<T> {
248 const NAME: &'static str = "ContractError";
249
250 const MIN_DATA_LENGTH: usize = if T::MIN_DATA_LENGTH < 32 { T::MIN_DATA_LENGTH } else { 32 };
252
253 const COUNT: usize = T::COUNT + 2;
254
255 #[inline]
256 fn selector(&self) -> [u8; 4] {
257 match self {
258 Self::CustomError(error) => error.selector(),
259 Self::Panic(_) => Panic::SELECTOR,
260 Self::Revert(_) => Revert::SELECTOR,
261 }
262 }
263
264 #[inline]
265 fn selector_at(i: usize) -> Option<[u8; 4]> {
266 if i < T::COUNT {
267 T::selector_at(i)
268 } else {
269 match i - T::COUNT {
270 0 => Some(Revert::SELECTOR),
271 1 => Some(Panic::SELECTOR),
272 _ => None,
273 }
274 }
275 }
276
277 #[inline]
278 fn valid_selector(selector: [u8; 4]) -> bool {
279 match selector {
280 Revert::SELECTOR | Panic::SELECTOR => true,
281 s => T::valid_selector(s),
282 }
283 }
284
285 #[inline]
286 fn abi_decode_raw(selector: [u8; 4], data: &[u8]) -> Result<Self> {
287 match selector {
288 Revert::SELECTOR => Revert::abi_decode_raw(data).map(Self::Revert),
289 Panic::SELECTOR => Panic::abi_decode_raw(data).map(Self::Panic),
290 s => T::abi_decode_raw(s, data).map(Self::CustomError),
291 }
292 }
293
294 #[inline]
295 fn abi_decode_raw_validate(selector: [u8; 4], data: &[u8]) -> Result<Self> {
296 match selector {
297 Revert::SELECTOR => {
298 <Revert as SolError>::abi_decode_raw_validate(data).map(Self::Revert)
299 }
300 Panic::SELECTOR => <Panic as SolError>::abi_decode_raw_validate(data).map(Self::Panic),
301 s => T::abi_decode_raw_validate(s, data).map(Self::CustomError),
302 }
303 }
304
305 #[inline]
306 fn abi_encoded_size(&self) -> usize {
307 match self {
308 Self::CustomError(error) => error.abi_encoded_size(),
309 Self::Panic(panic) => panic.abi_encoded_size(),
310 Self::Revert(revert) => revert.abi_encoded_size(),
311 }
312 }
313
314 #[inline]
315 fn abi_encode_raw(&self, out: &mut Vec<u8>) {
316 match self {
317 Self::CustomError(error) => error.abi_encode_raw(out),
318 Self::Panic(panic) => panic.abi_encode_raw(out),
319 Self::Revert(revert) => revert.abi_encode_raw(out),
320 }
321 }
322}
323
324impl<T> ContractError<T> {
325 #[inline]
327 pub const fn is_custom_error(&self) -> bool {
328 matches!(self, Self::CustomError(_))
329 }
330
331 #[inline]
334 pub const fn as_custom_error(&self) -> Option<&T> {
335 match self {
336 Self::CustomError(inner) => Some(inner),
337 _ => None,
338 }
339 }
340
341 #[inline]
344 pub fn as_custom_error_mut(&mut self) -> Option<&mut T> {
345 match self {
346 Self::CustomError(inner) => Some(inner),
347 _ => None,
348 }
349 }
350
351 #[inline]
353 pub const fn is_revert(&self) -> bool {
354 matches!(self, Self::Revert(_))
355 }
356
357 #[inline]
360 pub const fn as_revert(&self) -> Option<&Revert> {
361 match self {
362 Self::Revert(inner) => Some(inner),
363 _ => None,
364 }
365 }
366
367 #[inline]
370 pub fn as_revert_mut(&mut self) -> Option<&mut Revert> {
371 match self {
372 Self::Revert(inner) => Some(inner),
373 _ => None,
374 }
375 }
376
377 #[inline]
379 pub const fn is_panic(&self) -> bool {
380 matches!(self, Self::Panic(_))
381 }
382
383 #[inline]
386 pub const fn as_panic(&self) -> Option<&Panic> {
387 match self {
388 Self::Panic(inner) => Some(inner),
389 _ => None,
390 }
391 }
392
393 #[inline]
396 pub fn as_panic_mut(&mut self) -> Option<&mut Panic> {
397 match self {
398 Self::Panic(inner) => Some(inner),
399 _ => None,
400 }
401 }
402}
403
404pub type GenericRevertReason = RevertReason<Infallible>;
406
407#[derive(Clone, Debug, PartialEq, Eq)]
417pub enum RevertReason<T> {
418 ContractError(ContractError<T>),
420 RawString(String),
422}
423
424impl<T: fmt::Display> fmt::Display for RevertReason<T> {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 match self {
427 Self::ContractError(error) => error.fmt(f),
428 Self::RawString(raw_string) => f.write_str(raw_string),
429 }
430 }
431}
432
433impl<T> From<ContractError<T>> for RevertReason<T> {
435 fn from(error: ContractError<T>) -> Self {
436 Self::ContractError(error)
437 }
438}
439
440impl<T> From<Revert> for RevertReason<T> {
442 fn from(revert: Revert) -> Self {
443 Self::ContractError(ContractError::Revert(revert))
444 }
445}
446
447impl<T> From<String> for RevertReason<T> {
449 fn from(raw_string: String) -> Self {
450 Self::RawString(raw_string)
451 }
452}
453
454impl<T: SolInterface> RevertReason<T>
455where
456 Self: From<ContractError<Infallible>>,
457{
458 pub fn decode(out: &[u8]) -> Option<Self> {
467 if let Ok(error) = ContractError::<T>::abi_decode(out) {
469 return Some(error.into());
470 }
471
472 if let Ok(decoded_string) = core::str::from_utf8(out) {
474 return Some(decoded_string.to_string().into());
475 }
476
477 None
479 }
480}
481
482impl<T: SolInterface + fmt::Display> RevertReason<T> {
483 #[allow(clippy::inherent_to_string_shadow_display)]
485 pub fn to_string(&self) -> String {
486 match self {
487 Self::ContractError(error) => error.to_string(),
488 Self::RawString(raw_string) => raw_string.clone(),
489 }
490 }
491}
492
493impl<T> RevertReason<T> {
494 pub fn as_raw_error(&self) -> Option<&str> {
496 match self {
497 Self::RawString(error) => Some(error.as_str()),
498 _ => None,
499 }
500 }
501
502 pub const fn as_contract_error(&self) -> Option<&ContractError<T>> {
504 match self {
505 Self::ContractError(error) => Some(error),
506 _ => None,
507 }
508 }
509
510 pub const fn is_revert(&self) -> bool {
512 matches!(self, Self::ContractError(ContractError::Revert(_)))
513 }
514
515 pub const fn is_panic(&self) -> bool {
517 matches!(self, Self::ContractError(ContractError::Panic(_)))
518 }
519
520 pub const fn is_custom_error(&self) -> bool {
522 matches!(self, Self::ContractError(ContractError::CustomError(_)))
523 }
524}
525
526pub struct Selectors<T> {
533 index: usize,
534 _marker: PhantomData<T>,
535}
536
537impl<T> Clone for Selectors<T> {
538 fn clone(&self) -> Self {
539 Self { index: self.index, _marker: PhantomData }
540 }
541}
542
543impl<T> fmt::Debug for Selectors<T> {
544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545 f.debug_struct("Selectors").field("index", &self.index).finish()
546 }
547}
548
549impl<T> Selectors<T> {
550 #[inline]
551 const fn new() -> Self {
552 Self { index: 0, _marker: PhantomData }
553 }
554}
555
556impl<T: SolInterface> Iterator for Selectors<T> {
557 type Item = [u8; 4];
558
559 #[inline]
560 fn next(&mut self) -> Option<Self::Item> {
561 let selector = T::selector_at(self.index)?;
562 self.index += 1;
563 Some(selector)
564 }
565
566 #[inline]
567 fn size_hint(&self) -> (usize, Option<usize>) {
568 let exact = self.len();
569 (exact, Some(exact))
570 }
571
572 #[inline]
573 fn count(self) -> usize {
574 self.len()
575 }
576}
577
578impl<T: SolInterface> ExactSizeIterator for Selectors<T> {
579 #[inline]
580 fn len(&self) -> usize {
581 T::COUNT - self.index
582 }
583}
584
585impl<T: SolInterface> FusedIterator for Selectors<T> {}
586
587#[cfg(test)]
588mod tests {
589 use super::*;
590 use alloy_primitives::{keccak256, U256};
591
592 fn sel(s: &str) -> [u8; 4] {
593 keccak256(s)[..4].try_into().unwrap()
594 }
595
596 #[test]
597 fn generic_contract_error_enum() {
598 assert_eq!(
599 GenericContractError::selectors().collect::<Vec<_>>(),
600 [sel("Error(string)"), sel("Panic(uint256)")]
601 );
602 }
603
604 #[test]
605 fn contract_error_enum_1() {
606 crate::sol! {
607 #[derive(Debug, PartialEq, Eq)]
608 contract C {
609 error Err1();
610 }
611 }
612
613 assert_eq!(C::CErrors::COUNT, 1);
614 assert_eq!(C::CErrors::MIN_DATA_LENGTH, 0);
615 assert_eq!(ContractError::<C::CErrors>::COUNT, 1 + 2);
616 assert_eq!(ContractError::<C::CErrors>::MIN_DATA_LENGTH, 0);
617
618 assert_eq!(C::CErrors::SELECTORS, [sel("Err1()")]);
619 assert_eq!(
620 ContractError::<C::CErrors>::selectors().collect::<Vec<_>>(),
621 vec![sel("Err1()"), sel("Error(string)"), sel("Panic(uint256)")],
622 );
623
624 for selector in C::CErrors::selectors() {
625 assert!(C::CErrors::valid_selector(selector));
626 }
627
628 for selector in ContractError::<C::CErrors>::selectors() {
629 assert!(ContractError::<C::CErrors>::valid_selector(selector));
630 }
631
632 let err1 = || C::Err1 {};
633 let errors_err1 = || C::CErrors::Err1(err1());
634 let contract_error_err1 = || ContractError::<C::CErrors>::CustomError(errors_err1());
635 let encoded_data = err1().abi_encode();
636 let selector = C::Err1::SELECTOR;
637 let raw_data = &encoded_data[4..];
638
639 assert_eq!(encoded_data[..4], selector);
640 assert_eq!(errors_err1().abi_encode(), encoded_data);
641 assert_eq!(contract_error_err1().abi_encode(), encoded_data);
642
643 assert_eq!(C::Err1::abi_decode(&encoded_data), Ok(err1()));
644 assert_eq!(
645 <C::CErrors as SolInterface>::abi_decode_validate(&encoded_data),
646 Ok(errors_err1())
647 );
648 assert_eq!(
649 <ContractError<C::CErrors> as SolInterface>::abi_decode_validate(&encoded_data),
650 Ok(contract_error_err1())
651 );
652
653 assert_eq!(
654 <C::CErrors as SolInterface>::abi_decode_raw_validate(selector, raw_data),
655 Ok(errors_err1())
656 );
657 assert_eq!(
658 <ContractError<C::CErrors> as SolInterface>::abi_decode_raw_validate(
659 selector, raw_data
660 ),
661 Ok(contract_error_err1())
662 );
663
664 for selector in C::CErrors::selectors() {
665 assert!(C::CErrors::valid_selector(selector));
666 }
667
668 for selector in ContractError::<C::CErrors>::selectors() {
669 assert!(ContractError::<C::CErrors>::valid_selector(selector));
670 }
671 }
672
673 #[test]
674 fn contract_error_enum_2() {
675 crate::sol! {
676 #[derive(Debug, PartialEq, Eq)]
677 contract C {
678 error Err1();
679 error Err2(uint256);
680 error Err3(string);
681 }
682 }
683
684 assert_eq!(C::CErrors::COUNT, 3);
685 assert_eq!(C::CErrors::MIN_DATA_LENGTH, 0);
686 assert_eq!(ContractError::<C::CErrors>::COUNT, 2 + 3);
687 assert_eq!(ContractError::<C::CErrors>::MIN_DATA_LENGTH, 0);
688
689 assert_eq!(
691 C::CErrors::SELECTORS,
692 [sel("Err3(string)"), sel("Err2(uint256)"), sel("Err1()")]
693 );
694 assert_eq!(
695 ContractError::<C::CErrors>::selectors().collect::<Vec<_>>(),
696 [
697 sel("Err3(string)"),
698 sel("Err2(uint256)"),
699 sel("Err1()"),
700 sel("Error(string)"),
701 sel("Panic(uint256)"),
702 ],
703 );
704
705 let err1 = || C::Err1 {};
706 let errors_err1 = || C::CErrors::Err1(err1());
707 let contract_error_err1 = || ContractError::<C::CErrors>::CustomError(errors_err1());
708 let encoded_data1 = err1().abi_encode();
709 let selector1 = C::Err1::SELECTOR;
710 let raw_data1 = &encoded_data1[4..];
711
712 assert_eq!(encoded_data1[..4], selector1);
713 assert_eq!(errors_err1().abi_encode(), encoded_data1);
714 assert_eq!(contract_error_err1().abi_encode(), encoded_data1);
715
716 assert_eq!(C::Err1::abi_decode(&encoded_data1), Ok(err1()));
717 assert_eq!(
718 <C::CErrors as SolInterface>::abi_decode_validate(&encoded_data1),
719 Ok(errors_err1())
720 );
721 assert_eq!(
722 <ContractError<C::CErrors> as SolInterface>::abi_decode_validate(&encoded_data1),
723 Ok(contract_error_err1())
724 );
725
726 assert_eq!(
727 <C::CErrors as SolInterface>::abi_decode_raw_validate(selector1, raw_data1),
728 Ok(errors_err1())
729 );
730 assert_eq!(
731 <ContractError<C::CErrors> as SolInterface>::abi_decode_raw_validate(
732 selector1, raw_data1
733 ),
734 Ok(contract_error_err1())
735 );
736
737 let err2 = || C::Err2(U256::from(42));
738 let errors_err2 = || C::CErrors::Err2(err2());
739 let contract_error_err2 = || ContractError::<C::CErrors>::CustomError(errors_err2());
740 let encoded_data2 = err2().abi_encode();
741 let selector2 = C::Err2::SELECTOR;
742 let raw_data2 = &encoded_data2[4..];
743
744 assert_eq!(encoded_data2[..4], selector2);
745 assert_eq!(errors_err2().abi_encode(), encoded_data2);
746 assert_eq!(contract_error_err2().abi_encode(), encoded_data2);
747
748 assert_eq!(C::Err2::abi_decode(&encoded_data2), Ok(err2()));
749 assert_eq!(
750 <C::CErrors as SolInterface>::abi_decode_validate(&encoded_data2),
751 Ok(errors_err2())
752 );
753 assert_eq!(
754 <ContractError<C::CErrors> as SolInterface>::abi_decode_validate(&encoded_data2),
755 Ok(contract_error_err2())
756 );
757
758 assert_eq!(
759 <C::CErrors as SolInterface>::abi_decode_raw_validate(selector2, raw_data2),
760 Ok(errors_err2())
761 );
762 assert_eq!(
763 <ContractError<C::CErrors> as SolInterface>::abi_decode_raw_validate(
764 selector2, raw_data2
765 ),
766 Ok(contract_error_err2())
767 );
768
769 let err3 = || C::Err3("hello".into());
770 let errors_err3 = || C::CErrors::Err3(err3());
771 let contract_error_err3 = || ContractError::<C::CErrors>::CustomError(errors_err3());
772 let encoded_data3 = err3().abi_encode();
773 let selector3 = C::Err3::SELECTOR;
774 let raw_data3 = &encoded_data3[4..];
775
776 assert_eq!(encoded_data3[..4], selector3);
777 assert_eq!(errors_err3().abi_encode(), encoded_data3);
778 assert_eq!(contract_error_err3().abi_encode(), encoded_data3);
779
780 assert_eq!(C::Err3::abi_decode(&encoded_data3), Ok(err3()));
781 assert_eq!(
782 <C::CErrors as SolInterface>::abi_decode_validate(&encoded_data3),
783 Ok(errors_err3())
784 );
785 assert_eq!(
786 <ContractError<C::CErrors> as SolInterface>::abi_decode_validate(&encoded_data3),
787 Ok(contract_error_err3())
788 );
789
790 assert_eq!(
791 <C::CErrors as SolInterface>::abi_decode_raw_validate(selector3, raw_data3),
792 Ok(errors_err3())
793 );
794 assert_eq!(
795 <ContractError<C::CErrors> as SolInterface>::abi_decode_raw_validate(
796 selector3, raw_data3
797 ),
798 Ok(contract_error_err3())
799 );
800
801 for selector in C::CErrors::selectors() {
802 assert!(C::CErrors::valid_selector(selector));
803 }
804
805 for selector in ContractError::<C::CErrors>::selectors() {
806 assert!(ContractError::<C::CErrors>::valid_selector(selector));
807 }
808 }
809}