Skip to content

Commit

Permalink
feat(sol-macro): #[sol] attributes and JSON ABI support (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes authored Jul 10, 2023
1 parent 6fe3636 commit 32a2356
Show file tree
Hide file tree
Showing 47 changed files with 1,761 additions and 408 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@clippy
- run: cargo clippy --workspace --all-targets
- run: cargo clippy --workspace --all-targets --all-features
env:
RUSTFLAGS: -Dwarnings

Expand Down
3 changes: 1 addition & 2 deletions crates/dyn-abi/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use core::fmt;

use alloy_sol_type_parser::Error as TypeParserError;
use core::fmt;

/// Dynamic ABI result type.
pub type DynAbiResult<T, E = DynAbiError> = core::result::Result<T, E>;
Expand Down
1 change: 0 additions & 1 deletion crates/dyn-abi/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use crate::{DynAbiError, DynAbiResult, DynSolType};
use alloc::vec::Vec;

use alloy_json_abi::{EventParam, Param};
use alloy_sol_type_parser::{
Error as TypeStrError, RootType, TupleSpecifier, TypeSpecifier, TypeStem,
Expand Down
82 changes: 35 additions & 47 deletions crates/json-abi/src/internal_type.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use core::fmt;

use alloc::string::{String, ToString};

use alloy_sol_type_parser::TypeSpecifier;
use core::fmt;
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};

/// The contract internal type. This could be a regular solidity type, a
Expand Down Expand Up @@ -196,17 +194,17 @@ impl InternalType {
#[inline]
pub(crate) fn as_borrowed(&self) -> BorrowedInternalType<'_> {
match self {
InternalType::AddressPayable(s) => BorrowedInternalType::AddressPayable(s),
InternalType::Contract(s) => BorrowedInternalType::Contract(s),
InternalType::Enum { contract, ty } => BorrowedInternalType::Enum {
Self::AddressPayable(s) => BorrowedInternalType::AddressPayable(s),
Self::Contract(s) => BorrowedInternalType::Contract(s),
Self::Enum { contract, ty } => BorrowedInternalType::Enum {
contract: contract.as_deref(),
ty,
},
InternalType::Struct { contract, ty } => BorrowedInternalType::Struct {
Self::Struct { contract, ty } => BorrowedInternalType::Struct {
contract: contract.as_deref(),
ty,
},
InternalType::Other { contract, ty } => BorrowedInternalType::Other {
Self::Other { contract, ty } => BorrowedInternalType::Other {
contract: contract.as_deref(),
ty,
},
Expand Down Expand Up @@ -234,48 +232,41 @@ pub(crate) enum BorrowedInternalType<'a> {

impl fmt::Display for BorrowedInternalType<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BorrowedInternalType::AddressPayable(s) => f.write_str(s),
BorrowedInternalType::Contract(s) => write!(f, "contract {}", s),
BorrowedInternalType::Enum { contract, ty } => {
if let Some(c) = contract {
write!(f, "enum {}.{}", c, ty)
} else {
write!(f, "enum {}", ty)
}
match *self {
Self::AddressPayable(s) => f.write_str(s),
Self::Contract(s) => {
f.write_str("contract ")?;
f.write_str(s)
}
BorrowedInternalType::Struct { contract, ty } => {
if let Some(c) = contract {
write!(f, "struct {}.{}", c, ty)
} else {
write!(f, "struct {}", ty)
Self::Enum { contract, ty }
| Self::Struct { contract, ty }
| Self::Other { contract, ty } => {
match self {
Self::Enum { .. } => f.write_str("enum ")?,
Self::Struct { .. } => f.write_str("struct ")?,
Self::Other { .. } => {}
_ => unreachable!(),
}
}
BorrowedInternalType::Other { contract, ty } => {
if let Some(c) = contract {
write!(f, "{}.{}", c, ty)
} else {
write!(f, "{}", ty)
f.write_str(c)?;
f.write_str(".")?;
}
f.write_str(ty)
}
}
}
}

impl Serialize for BorrowedInternalType<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[inline]
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.collect_str(self)
}
}

impl<'de: 'a, 'a> Deserialize<'de> for BorrowedInternalType<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[inline]
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(ItVisitor)
}
}
Expand All @@ -284,41 +275,41 @@ impl<'a> BorrowedInternalType<'a> {
/// Instantiate a borrowed internal type by parsing a string.
fn parse(v: &'a str) -> Option<Self> {
if v.starts_with("address payable") {
return Some(BorrowedInternalType::AddressPayable(v))
return Some(Self::AddressPayable(v))
}
if let Some(body) = v.strip_prefix("enum ") {
if let Some((contract, ty)) = body.split_once('.') {
Some(BorrowedInternalType::Enum {
Some(Self::Enum {
contract: Some(contract),
ty,
})
} else {
Some(BorrowedInternalType::Enum {
Some(Self::Enum {
contract: None,
ty: body,
})
}
} else if let Some(body) = v.strip_prefix("struct ") {
if let Some((contract, ty)) = body.split_once('.') {
Some(BorrowedInternalType::Struct {
Some(Self::Struct {
contract: Some(contract),
ty,
})
} else {
Some(BorrowedInternalType::Struct {
Some(Self::Struct {
contract: None,
ty: body,
})
}
} else if let Some(body) = v.strip_prefix("contract ") {
Some(BorrowedInternalType::Contract(body))
Some(Self::Contract(body))
} else if let Some((contract, ty)) = v.split_once('.') {
Some(BorrowedInternalType::Other {
Some(Self::Other {
contract: Some(contract),
ty,
})
} else {
Some(BorrowedInternalType::Other {
Some(Self::Other {
contract: None,
ty: v,
})
Expand All @@ -335,10 +326,7 @@ impl<'de> Visitor<'de> for ItVisitor {
write!(formatter, "a valid internal type")
}

fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
BorrowedInternalType::parse(v).ok_or_else(|| {
E::invalid_value(serde::de::Unexpected::Str(v), &"a valid internal type")
})
Expand Down
2 changes: 2 additions & 0 deletions crates/json-abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub use internal_type::InternalType;

pub(crate) mod utils;

pub use alloy_sol_type_parser as parser;

/// A JSON ABI function's state mutability.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
Expand Down
11 changes: 5 additions & 6 deletions crates/json-abi/src/param.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use crate::{
internal_type::BorrowedInternalType,
utils::{validate_identifier, validate_ty},
InternalType,
};
use alloc::{
borrow::{Cow, ToOwned},
string::String,
Expand All @@ -7,12 +12,6 @@ use alloy_sol_type_parser::TypeSpecifier;
use core::fmt;
use serde::{de::Unexpected, Deserialize, Deserializer, Serialize, Serializer};

use crate::{
internal_type::BorrowedInternalType,
utils::{validate_identifier, validate_ty},
InternalType,
};

/// JSON specification of a parameter.
///
/// Parameters are the inputs and outputs of [Function]s, and the fields of
Expand Down
1 change: 1 addition & 0 deletions crates/json-abi/tests/abi/Udvts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"Udvts.ItemType","name":"itemType","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct Udvts.OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"Udvts.ItemType","name":"itemType","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct Udvts.ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"Udvts.OrderType","name":"orderType","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct Udvts.OrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct Udvts.AdvancedOrder[]","name":"a","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"Udvts.Side","name":"side","type":"bool"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct Udvts.CriteriaResolver[]","name":"b","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct Udvts.FulfillmentComponent[][]","name":"c","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct Udvts.FulfillmentComponent[][]","name":"d","type":"tuple[][]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"maximumFulfilled","type":"uint256"}],"name":"fulfillAvailableAdvancedOrders","outputs":[{"internalType":"bool[]","name":"e","type":"bool[]"},{"components":[{"components":[{"internalType":"Udvts.ItemType","name":"itemType","type":"bytes32"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct Udvts.ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Udvts.Execution[]","name":"f","type":"tuple[]"}],"stateMutability":"payable","type":"function"}]
1 change: 1 addition & 0 deletions crates/json-abi/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ abi_parse_tests! {
large_structs("abi/LargeStructs.json", 4)
large_tuple("abi/LargeTuple.json", 1)
seaport("abi/Seaport.json", 69)
udvts("abi/Udvts.json", 1)
}

fn parse_test(s: &str, len: usize) {
Expand Down
9 changes: 9 additions & 0 deletions crates/sol-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,17 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
syn-solidity = { workspace = true, features = ["visit", "visit-mut"] }

dunce = "1"
heck = "0.4"
proc-macro2.workspace = true
quote.workspace = true
syn = { workspace = true, features = ["extra-traits"] }
tiny-keccak = { workspace = true, features = ["keccak"] }

# json
alloy-json-abi = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_json = { workspace = true, optional = true }

[features]
json = ["dep:alloy-json-abi", "dep:serde", "dep:serde_json"]
Loading

0 comments on commit 32a2356

Please sign in to comment.