Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(json-abi): normalize $ to _ in identifiers in to_sol #747

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 46 additions & 8 deletions crates/json-abi/src/to_sol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
EventParam, InternalType, JsonAbi, Param, StateMutability,
};
use alloc::{
borrow::Cow,
collections::{BTreeMap, BTreeSet},
string::String,
vec::Vec,
Expand All @@ -18,6 +19,7 @@ use core::{
pub struct ToSolConfig {
print_constructors: bool,
enums_as_udvt: bool,
for_sol_macro: bool,
}

impl Default for ToSolConfig {
Expand All @@ -31,7 +33,7 @@ impl ToSolConfig {
/// Creates a new configuration with default settings.
#[inline]
pub const fn new() -> Self {
Self { print_constructors: false, enums_as_udvt: true }
Self { print_constructors: false, enums_as_udvt: true, for_sol_macro: false }
}

/// Sets whether to print constructors. Default: `false`.
Expand All @@ -48,6 +50,14 @@ impl ToSolConfig {
self.enums_as_udvt = yes;
self
}

/// Sets whether to normalize the output for the [`sol!`] macro. Default: `false`.
///
/// [`sol!`]: https://docs.rs/alloy-sol-macro/latest/alloy_sol_macro/macro.sol.html
pub const fn for_sol_macro(mut self, yes: bool) -> Self {
self.for_sol_macro = yes;
self
}
}

pub(crate) trait ToSol {
Expand Down Expand Up @@ -97,6 +107,27 @@ impl<'a> SolPrinter<'a> {
fn indent(&mut self) {
self.push_str(" ");
}

/// Normalizes `s` as a Rust identifier and pushes it to the buffer.
///
/// See [`Self::normalize_ident`] for more details.
fn push_ident(&mut self, s: &str) {
let s = self.normalize_ident(s);
self.push_str(&s);
}

/// Normalizes `s` as a Rust identifier.
///
/// All Solidity identifiers are also valid Rust identifiers, except for `$`.
/// This function replaces `$` with `_` if the configuration is set to normalize for the `sol!`
/// macro.
fn normalize_ident<'b>(&self, s: &'b str) -> Cow<'b, str> {
if self.config.for_sol_macro && s.contains('$') {
Cow::Owned(s.replace('$', "_"))
} else {
Cow::Borrowed(s)
}
}
}

impl JsonAbi {
Expand Down Expand Up @@ -311,19 +342,19 @@ impl ToSol for It<'_> {
match self.kind {
ItKind::Enum => {
out.push_str("type ");
out.push_str(self.name);
out.push_ident(self.name);
out.push_str(" is uint8;");
}
ItKind::Udvt(ty) => {
out.push_str("type ");
out.push_str(self.name);
out.push_ident(self.name);
out.push_str(" is ");
out.push_str(ty);
out.push(';');
}
ItKind::Struct(components) => {
out.push_str("struct ");
out.push_str(self.name);
out.push_ident(self.name);
out.push_str(" {\n");
for component in components {
out.indent();
Expand Down Expand Up @@ -483,10 +514,17 @@ impl<IN: ToSol> ToSol for AbiFunction<'_, IN> {
out.print_param_location = true;
}

// TODO: Enable once `#[sol(rename)]` is implemented.
// if let Some(name) = self.name {
// if out.config.for_sol_macro && name.contains('$') {
// write!(out, "#[sol(rename = \"{name}\")]").unwrap();
// }
// }

out.push_str(self.kw.as_str());
if let Some(name) = self.name {
out.push(' ');
out.push_str(name);
out.push_ident(name);
}

out.push('(');
Expand Down Expand Up @@ -616,11 +654,11 @@ fn param(
_ => {
if let Some(contract_name) = contract_name {
if contract_name != out.name {
out.push_str(contract_name);
out.push_ident(contract_name);
out.push('.');
}
}
out.push_str(type_name);
out.push_ident(type_name);
}
}

Expand All @@ -639,6 +677,6 @@ fn param(
}
if !name.is_empty() {
out.push(' ');
out.push_str(name);
out.push_ident(name);
}
}
6 changes: 4 additions & 2 deletions crates/json-abi/tests/abi.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alloy_json_abi::{AbiItem, EventParam, JsonAbi, Param};
use alloy_json_abi::{AbiItem, EventParam, JsonAbi, Param, ToSolConfig};
use pretty_assertions::assert_eq;
use std::{
collections::HashMap,
Expand Down Expand Up @@ -86,7 +86,7 @@ fn to_sol_test(path: &str, abi: &JsonAbi, run_solc: bool) {
// Ignore constructors for Solc tests.
abi.constructor = None;
abi.dedup();
let actual = abi.to_sol(name, None);
let actual = abi.to_sol(name, Some(ToSolConfig::new().for_sol_macro(true)));

ensure_file_contents(&sol_path, &actual);

Expand All @@ -98,6 +98,8 @@ fn to_sol_test(path: &str, abi: &JsonAbi, run_solc: bool) {
| "UniswapV1Exchange"
// https://github.com/alloy-rs/core/issues/744
| "DelegationManager"
// https://github.com/alloy-rs/core/issues/746
| "Bootstrap"
) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions crates/json-abi/tests/abi/Bootstrap.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"type":"fallback","stateMutability":"payable"},{"type":"receive","stateMutability":"payable"},{"type":"function","name":"_getInitMSACalldata","inputs":[{"name":"$valdiators","type":"tuple[]","internalType":"struct BootstrapConfig[]","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"$executors","type":"tuple[]","internalType":"struct BootstrapConfig[]","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"_hook","type":"tuple","internalType":"struct BootstrapConfig","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"_fallbacks","type":"tuple[]","internalType":"struct BootstrapConfig[]","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]}],"outputs":[{"name":"init","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"entryPoint","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getActiveFallbackHandler","inputs":[{"name":"functionSig","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"tuple","internalType":"struct ModuleManager.FallbackHandler","components":[{"name":"handler","type":"address","internalType":"address"},{"name":"calltype","type":"bytes1","internalType":"CallType"}]}],"stateMutability":"view"},{"type":"function","name":"getActiveHook","inputs":[],"outputs":[{"name":"hook","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getExecutorsPaginated","inputs":[{"name":"cursor","type":"address","internalType":"address"},{"name":"size","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"array","type":"address[]","internalType":"address[]"},{"name":"next","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getValidatorsPaginated","inputs":[{"name":"cursor","type":"address","internalType":"address"},{"name":"size","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"array","type":"address[]","internalType":"address[]"},{"name":"next","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"initMSA","inputs":[{"name":"$valdiators","type":"tuple[]","internalType":"struct BootstrapConfig[]","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"$executors","type":"tuple[]","internalType":"struct BootstrapConfig[]","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"_hook","type":"tuple","internalType":"struct BootstrapConfig","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"_fallbacks","type":"tuple[]","internalType":"struct BootstrapConfig[]","components":[{"name":"module","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"singleInitMSA","inputs":[{"name":"validator","type":"address","internalType":"contract IModule"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"error","name":"AccountAccessUnauthorized","inputs":[]},{"type":"error","name":"CannotRemoveLastValidator","inputs":[]},{"type":"error","name":"HookAlreadyInstalled","inputs":[{"name":"currentHook","type":"address","internalType":"address"}]},{"type":"error","name":"HookPostCheckFailed","inputs":[]},{"type":"error","name":"InvalidModule","inputs":[{"name":"module","type":"address","internalType":"address"}]},{"type":"error","name":"LinkedList_EntryAlreadyInList","inputs":[{"name":"entry","type":"address","internalType":"address"}]},{"type":"error","name":"LinkedList_InvalidEntry","inputs":[{"name":"entry","type":"address","internalType":"address"}]},{"type":"error","name":"LinkedList_InvalidPage","inputs":[]},{"type":"error","name":"NoFallbackHandler","inputs":[{"name":"selector","type":"bytes4","internalType":"bytes4"}]}]
37 changes: 37 additions & 0 deletions crates/json-abi/tests/abi/Bootstrap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
library ModuleManager {
struct FallbackHandler {
address handler;
CallType calltype;
}
}

interface Bootstrap {
type CallType is bytes1;
struct BootstrapConfig {
address module;
bytes data;
}

error AccountAccessUnauthorized();
error CannotRemoveLastValidator();
error HookAlreadyInstalled(address currentHook);
error HookPostCheckFailed();
error InvalidModule(address module);
error LinkedList_EntryAlreadyInList(address entry);
error LinkedList_InvalidEntry(address entry);
error LinkedList_InvalidPage();
error NoFallbackHandler(bytes4 selector);

fallback() external payable;

receive() external payable;

function _getInitMSACalldata(BootstrapConfig[] memory _valdiators, BootstrapConfig[] memory _executors, BootstrapConfig memory _hook, BootstrapConfig[] memory _fallbacks) external view returns (bytes memory init);
function entryPoint() external view returns (address);
function getActiveFallbackHandler(bytes4 functionSig) external view returns (ModuleManager.FallbackHandler memory);
function getActiveHook() external view returns (address hook);
function getExecutorsPaginated(address cursor, uint256 size) external view returns (address[] memory array, address next);
function getValidatorsPaginated(address cursor, uint256 size) external view returns (address[] memory array, address next);
function initMSA(BootstrapConfig[] memory _valdiators, BootstrapConfig[] memory _executors, BootstrapConfig memory _hook, BootstrapConfig[] memory _fallbacks) external;
function singleInitMSA(address validator, bytes memory data) external;
}
1 change: 1 addition & 0 deletions crates/json-abi/tests/abi/DollarIdentifiers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"components":[{"internalType":"uint256","name":"$dField","type":"uint256"}],"internalType":"struct DollarIdentifiers.$dStruct","name":"$dStructArg","type":"tuple"},{"internalType":"enum DollarIdentifiers.$dEnum","name":"$dEnumArg","type":"uint8"},{"internalType":"DollarIdentifiers.$dUDVT","name":"$dUDVTArg","type":"uint256"}],"name":"$dFunction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"$dPublicVariable","outputs":[{"internalType":"uint256","name":"$dField","type":"uint256"}],"stateMutability":"view","type":"function"}]
10 changes: 10 additions & 0 deletions crates/json-abi/tests/abi/DollarIdentifiers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
interface DollarIdentifiers {
type _dEnum is uint8;
type _dUDVT is uint256;
struct _dStruct {
uint256 _dField;
}

function _dFunction(_dStruct memory _dStructArg, _dEnum _dEnumArg, _dUDVT _dUDVTArg) external;
function _dPublicVariable() external view returns (uint256 _dField);
}
7 changes: 4 additions & 3 deletions crates/sol-macro-input/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Generated by the following Solidity interface...

let ast: ast::File = syn::parse2(tokens).map_err(|e| {
let msg = format!(
"failed to parse ABI-generated tokens into a Solidity AST: {e}.\n\
"failed to parse ABI-generated tokens into a Solidity AST for `{name}`: {e}.\n\
This is a bug. We would appreciate a bug report: \
https://github.com/alloy-rs/core/issues/new/choose"
);
Expand All @@ -105,14 +105,15 @@ Generated by the following Solidity interface...

fn abi_to_sol(name: &Ident, abi: &mut JsonAbi) -> String {
abi.dedup();
abi.to_sol(&name.to_string(), Some(ToSolConfig::new().print_constructors(true)))
let config = ToSolConfig::new().print_constructors(true).for_sol_macro(true);
abi.to_sol(&name.to_string(), Some(config))
}

/// Returns `sol!` tokens.
pub fn tokens_for_sol(name: &Ident, sol: &str) -> Result<TokenStream> {
let mk_err = |s: &str| {
let msg = format!(
"`JsonAbi::to_sol` generated invalid Rust tokens: {s}\n\
"`JsonAbi::to_sol` generated invalid Rust tokens for `{name}`: {s}\n\
This is a bug. We would appreciate a bug report: \
https://github.com/alloy-rs/core/issues/new/choose"
);
Expand Down
6 changes: 6 additions & 0 deletions crates/sol-types/tests/macros/sol/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,9 @@ fn balancer_v2_vault() {
// fn eigenlayer_delegation_manager() {
// sol!(DelegationManager, "../json-abi/tests/abi/DelegationManager.json");
// }

// TODO: https://github.com/alloy-rs/core/issues/746
// #[test]
// fn smartsession_bootstrap() {
// sol!(Bootstrap, "../json-abi/tests/abi/Bootstrap.json");
// }
1 change: 0 additions & 1 deletion scripts/check_no_std.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ crates=(
alloy-core-sol-test
alloy-dyn-abi
alloy-json-abi
alloy-json-abi
alloy-primitives
# alloy-sol-macro
# alloy-sol-macro-expander
Expand Down