use crate::{param::Param, serde_state_mutability_compat, utils::*, EventParam, StateMutability};
use alloc::{borrow::Cow, string::String, vec::Vec};
use alloy_primitives::{keccak256, Selector, B256};
use core::str::FromStr;
use parser::utils::ParsedSignature;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
macro_rules! abi_items {
($(
$(#[$attr:meta])*
$vis:vis struct $name:ident : $name_lower:literal {$(
$(#[$fattr:meta])*
$fvis:vis $field:ident : $type:ty,
)*}
)*) => {
$(
$(#[$attr])*
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename = $name_lower, rename_all = "camelCase", tag = "type")]
$vis struct $name {$(
$(#[$fattr])*
$fvis $field: $type,
)*}
impl From<$name> for AbiItem<'_> {
#[inline]
fn from(item: $name) -> Self {
AbiItem::$name(Cow::Owned(item))
}
}
impl<'a> From<&'a $name> for AbiItem<'a> {
#[inline]
fn from(item: &'a $name) -> Self {
AbiItem::$name(Cow::Borrowed(item))
}
}
)*
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum AbiItem<'a> {$(
#[doc = concat!("A JSON ABI [`", stringify!($name), "`].")]
$name(Cow<'a, $name>),
)*}
impl Serialize for AbiItem<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {$(
Self::$name(item) => item.serialize(serializer),
)*}
}
}
impl AbiItem<'_> {
#[inline]
pub const fn json_type(&self) -> &'static str {
match self {$(
Self::$name(_) => $name_lower,
)*}
}
}
};
}
abi_items! {
pub struct Constructor: "constructor" {
pub inputs: Vec<Param>,
#[serde(default, flatten, with = "serde_state_mutability_compat")]
pub state_mutability: StateMutability,
}
#[derive(Copy)]
pub struct Fallback: "fallback" {
#[serde(default, flatten, with = "serde_state_mutability_compat")]
pub state_mutability: StateMutability,
}
#[derive(Copy)]
pub struct Receive: "receive" {
#[serde(default, flatten, with = "serde_state_mutability_compat")]
pub state_mutability: StateMutability,
}
pub struct Function: "function" {
#[serde(deserialize_with = "validated_identifier")]
pub name: String,
pub inputs: Vec<Param>,
pub outputs: Vec<Param>,
#[serde(default, flatten, with = "serde_state_mutability_compat")]
pub state_mutability: StateMutability,
}
pub struct Event: "event" {
#[serde(deserialize_with = "validated_identifier")]
pub name: String,
pub inputs: Vec<EventParam>,
pub anonymous: bool,
}
pub struct Error: "error" {
#[serde(deserialize_with = "validated_identifier")]
pub name: String,
pub inputs: Vec<Param>,
}
}
#[inline]
fn validated_identifier<'de, D: Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> {
let s = String::deserialize(deserializer)?;
validate_identifier(&s)?;
Ok(s)
}
impl FromStr for AbiItem<'_> {
type Err = parser::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl AbiItem<'_> {
pub fn parse(mut input: &str) -> parser::Result<Self> {
let copy = input;
match parser::utils::parse_item_keyword(&mut input)? {
"constructor" => Constructor::parse(copy).map(Into::into),
"function" => Function::parse(input).map(Into::into),
"error" => Error::parse(input).map(Into::into),
"event" => Event::parse(input).map(Into::into),
keyword => Err(parser::Error::new(format_args!(
"invalid AbiItem keyword: {keyword:?}, \
expected one of \"constructor\", \"function\", \"error\", or \"event\""
))),
}
}
#[inline]
pub const fn debug_name(&self) -> &'static str {
match self {
AbiItem::Constructor(_) => "Constructor",
AbiItem::Fallback(_) => "Fallback",
AbiItem::Receive(_) => "Receive",
AbiItem::Function(_) => "Function",
AbiItem::Event(_) => "Event",
AbiItem::Error(_) => "Error",
}
}
#[inline]
pub fn name(&self) -> Option<&String> {
match self {
Self::Event(item) => Some(&item.name),
Self::Error(item) => Some(&item.name),
Self::Function(item) => Some(&item.name),
Self::Constructor(_) | Self::Fallback(_) | Self::Receive(_) => None,
}
}
#[inline]
pub fn name_mut(&mut self) -> Option<&mut String> {
match self {
Self::Event(item) => Some(&mut item.to_mut().name),
Self::Error(item) => Some(&mut item.to_mut().name),
Self::Function(item) => Some(&mut item.to_mut().name),
Self::Constructor(_) | Self::Fallback(_) | Self::Receive(_) => None,
}
}
#[inline]
pub fn state_mutability(&self) -> Option<StateMutability> {
match self {
Self::Constructor(item) => Some(item.state_mutability),
Self::Fallback(item) => Some(item.state_mutability),
Self::Receive(item) => Some(item.state_mutability),
Self::Function(item) => Some(item.state_mutability),
Self::Event(_) | Self::Error(_) => None,
}
}
#[inline]
pub fn state_mutability_mut(&mut self) -> Option<&mut StateMutability> {
match self {
Self::Constructor(item) => Some(&mut item.to_mut().state_mutability),
Self::Fallback(item) => Some(&mut item.to_mut().state_mutability),
Self::Receive(item) => Some(&mut item.to_mut().state_mutability),
Self::Function(item) => Some(&mut item.to_mut().state_mutability),
Self::Event(_) | Self::Error(_) => None,
}
}
#[inline]
pub fn inputs(&self) -> Option<&Vec<Param>> {
match self {
Self::Error(item) => Some(&item.inputs),
Self::Constructor(item) => Some(&item.inputs),
Self::Function(item) => Some(&item.inputs),
Self::Event(_) | Self::Fallback(_) | Self::Receive(_) => None,
}
}
#[inline]
pub fn inputs_mut(&mut self) -> Option<&mut Vec<Param>> {
match self {
Self::Error(item) => Some(&mut item.to_mut().inputs),
Self::Constructor(item) => Some(&mut item.to_mut().inputs),
Self::Function(item) => Some(&mut item.to_mut().inputs),
Self::Event(_) | Self::Fallback(_) | Self::Receive(_) => None,
}
}
#[inline]
pub fn event_inputs(&self) -> Option<&Vec<EventParam>> {
match self {
Self::Event(item) => Some(&item.inputs),
Self::Constructor(_)
| Self::Fallback(_)
| Self::Receive(_)
| Self::Error(_)
| Self::Function(_) => None,
}
}
#[inline]
pub fn event_inputs_mut(&mut self) -> Option<&mut Vec<EventParam>> {
match self {
Self::Event(item) => Some(&mut item.to_mut().inputs),
Self::Constructor(_)
| Self::Fallback(_)
| Self::Receive(_)
| Self::Error(_)
| Self::Function(_) => None,
}
}
#[inline]
pub fn outputs(&self) -> Option<&Vec<Param>> {
match self {
Self::Function(item) => Some(&item.outputs),
Self::Constructor(_)
| Self::Fallback(_)
| Self::Receive(_)
| Self::Error(_)
| Self::Event(_) => None,
}
}
#[inline]
pub fn outputs_mut(&mut self) -> Option<&mut Vec<Param>> {
match self {
Self::Function(item) => Some(&mut item.to_mut().outputs),
Self::Constructor(_)
| Self::Fallback(_)
| Self::Receive(_)
| Self::Error(_)
| Self::Event(_) => None,
}
}
}
impl FromStr for Constructor {
type Err = parser::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl Constructor {
#[inline]
pub fn parse(s: &str) -> parser::Result<Self> {
parse_sig::<false>(s).and_then(Self::parsed)
}
fn parsed(sig: ParsedSignature<Param>) -> parser::Result<Self> {
let ParsedSignature { name, inputs, outputs, anonymous, state_mutability } = sig;
if name != "constructor" {
return Err(parser::Error::new("constructors' name must be exactly \"constructor\""));
}
if !outputs.is_empty() {
return Err(parser::Error::new("constructors cannot have outputs"));
}
if anonymous {
return Err(parser::Error::new("constructors cannot be anonymous"));
}
Ok(Self { inputs, state_mutability: state_mutability.unwrap_or_default() })
}
}
impl FromStr for Error {
type Err = parser::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl Error {
#[inline]
pub fn parse(s: &str) -> parser::Result<Self> {
parse_maybe_prefixed(s, "error", parse_sig::<false>).and_then(Self::parsed)
}
fn parsed(sig: ParsedSignature<Param>) -> parser::Result<Self> {
let ParsedSignature { name, inputs, outputs, anonymous, state_mutability } = sig;
if !outputs.is_empty() {
return Err(parser::Error::new("errors cannot have outputs"));
}
if anonymous {
return Err(parser::Error::new("errors cannot be anonymous"));
}
if state_mutability.is_some() {
return Err(parser::Error::new("errors cannot have mutability"));
}
Ok(Self { name, inputs })
}
#[inline]
pub fn signature(&self) -> String {
signature(&self.name, &self.inputs, None)
}
#[inline]
pub fn selector(&self) -> Selector {
selector(&self.signature())
}
}
impl FromStr for Function {
type Err = parser::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl Function {
#[inline]
pub fn parse(s: &str) -> parser::Result<Self> {
parse_maybe_prefixed(s, "function", parse_sig::<true>).and_then(Self::parsed)
}
fn parsed(sig: ParsedSignature<Param>) -> parser::Result<Self> {
let ParsedSignature { name, inputs, outputs, anonymous, state_mutability } = sig;
if anonymous {
return Err(parser::Error::new("functions cannot be anonymous"));
}
Ok(Self { name, inputs, outputs, state_mutability: state_mutability.unwrap_or_default() })
}
#[inline]
pub fn signature(&self) -> String {
signature(&self.name, &self.inputs, None)
}
#[inline]
pub fn signature_with_outputs(&self) -> String {
signature(&self.name, &self.inputs, Some(&self.outputs))
}
#[inline]
pub fn full_signature(&self) -> String {
full_signature(&self.name, &self.inputs, Some(&self.outputs), self.state_mutability)
}
#[inline]
pub fn selector(&self) -> Selector {
selector(&self.signature())
}
}
impl FromStr for Event {
type Err = parser::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl Event {
#[inline]
pub fn parse(s: &str) -> parser::Result<Self> {
parse_maybe_prefixed(s, "event", parse_event_sig).and_then(Self::parsed)
}
fn parsed(sig: ParsedSignature<EventParam>) -> parser::Result<Self> {
let ParsedSignature { name, inputs, outputs, anonymous, state_mutability } = sig;
if !outputs.is_empty() {
return Err(parser::Error::new("events cannot have outputs"));
}
if state_mutability.is_some() {
return Err(parser::Error::new("events cannot have state mutability"));
}
Ok(Self { name, inputs, anonymous })
}
#[inline]
pub fn signature(&self) -> String {
event_signature(&self.name, &self.inputs)
}
#[inline]
pub fn full_signature(&self) -> String {
event_full_signature(&self.name, &self.inputs)
}
#[inline]
pub fn selector(&self) -> B256 {
keccak256(self.signature().as_bytes())
}
#[inline]
pub fn num_topics(&self) -> usize {
!self.anonymous as usize + self.inputs.iter().filter(|input| input.indexed).count()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn param2(kind: &str, name: &str) -> Param {
Param { ty: kind.into(), name: name.into(), internal_type: None, components: vec![] }
}
#[test]
fn parse_prefixes() {
for prefix in ["function", "error", "event"] {
let name = "foo";
let name1 = format!("{prefix} {name}");
let name2 = format!("{prefix}{name}");
assert_eq!(AbiItem::parse(&format!("{name1}()")).unwrap().name().unwrap(), name);
assert!(AbiItem::parse(&format!("{name2}()")).is_err());
}
}
#[test]
fn parse_function_prefix() {
let new = |name: &str| Function {
name: name.into(),
inputs: vec![],
outputs: vec![],
state_mutability: StateMutability::NonPayable,
};
assert_eq!(Function::parse("foo()"), Ok(new("foo")));
assert_eq!(Function::parse("function foo()"), Ok(new("foo")));
assert_eq!(Function::parse("functionfoo()"), Ok(new("functionfoo")));
assert_eq!(Function::parse("function functionfoo()"), Ok(new("functionfoo")));
}
#[test]
fn parse_event_prefix() {
let new = |name: &str| Event { name: name.into(), inputs: vec![], anonymous: false };
assert_eq!(Event::parse("foo()"), Ok(new("foo")));
assert_eq!(Event::parse("event foo()"), Ok(new("foo")));
assert_eq!(Event::parse("eventfoo()"), Ok(new("eventfoo")));
assert_eq!(Event::parse("event eventfoo()"), Ok(new("eventfoo")));
}
#[test]
fn parse_error_prefix() {
let new = |name: &str| Error { name: name.into(), inputs: vec![] };
assert_eq!(Error::parse("foo()"), Ok(new("foo")));
assert_eq!(Error::parse("error foo()"), Ok(new("foo")));
assert_eq!(Error::parse("errorfoo()"), Ok(new("errorfoo")));
assert_eq!(Error::parse("error errorfoo()"), Ok(new("errorfoo")));
}
#[test]
fn parse_full() {
assert_eq!(
Function::parse("function foo(uint256 a, uint256 b) external returns (uint256)"),
Ok(Function {
name: "foo".into(),
inputs: vec![param2("uint256", "a"), param2("uint256", "b")],
outputs: vec![param2("uint256", "")],
state_mutability: StateMutability::NonPayable,
})
);
assert_eq!(
Function::parse("function balanceOf(address owner) view returns (uint256 balance)"),
Ok(Function {
name: "balanceOf".into(),
inputs: vec![param2("address", "owner")],
outputs: vec![param2("uint256", "balance")],
state_mutability: StateMutability::View,
})
);
}
#[test]
fn parse_stack_overflow() {
let s = "error J((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((";
AbiItem::parse(s).unwrap_err();
}
}