use crate::{
decode::{Decode, DecodeError},
encode::Encode,
function::Selector,
};
use std::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
};
pub struct ErrorEncoder<D> {
pub selector: Selector,
_marker: PhantomData<*const D>,
}
impl<D> ErrorEncoder<D> {
pub const fn new(selector: Selector) -> Self {
Self {
selector,
_marker: PhantomData,
}
}
}
impl<D> ErrorEncoder<D>
where
D: Encode,
{
pub fn encode(&self, data: &D) -> Vec<u8> {
crate::encode_with_selector(self.selector, data)
}
}
impl<D> ErrorEncoder<D>
where
D: Decode,
{
pub fn decode(&self, data: &[u8]) -> Result<D, DecodeError> {
crate::decode_with_selector(self.selector, data)
}
}
impl<D> Debug for ErrorEncoder<D> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("ErrorEncoder")
.field("selector", &self.selector)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use ethprim::{address, uint, Address, U256};
use hex_literal::hex;
use std::borrow::Cow;
#[test]
fn round_trips_error_encoding() {
let insufficient_balance = ErrorEncoder::<(Address, U256)>::new(Selector(hex!("f6deaa04")));
let account = address!("0x0101010101010101010101010101010101010101");
let balance = uint!("4_200_000_000_000_000_000");
let data = hex!(
"f6deaa04
0000000000000000000000000101010101010101010101010101010101010101
0000000000000000000000000000000000000000000000003a4965bf58a40000"
);
assert_eq!(insufficient_balance.encode(&(account, balance)), data);
assert_eq!(
insufficient_balance.decode(&data).unwrap(),
(account, balance)
);
}
#[test]
fn revert_error() {
let revert = ErrorEncoder::<(Cow<str>,)>::new(Selector(hex!("08c379a0")));
let message = Cow::Borrowed("revert");
let fields = (message,);
let data = hex!(
"08c379a0
0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000006
7265766572740000000000000000000000000000000000000000000000000000"
);
assert_eq!(revert.encode(&fields), data);
assert_eq!(revert.decode(&data).unwrap(), fields);
}
}