-
Notifications
You must be signed in to change notification settings - Fork 795
feat: function call enums EthCall macro and more #517
Conversation
For anyone following along, here's how the codegen looks like #[doc = "Container type for all input parameters for the `getValue`function with signature `getValue()` and selector `[32, 150, 82, 85]`"]
#[derive(
Clone,
Debug,
Default,
Eq,
PartialEq,
ethers_contract :: EthCall,
ethers_contract :: EthDisplay,
)]
#[ethcall(name = "getValue", abi = "getValue()")]
pub struct GetValueCall();
#[doc = "Container type for all input parameters for the `setValue`function with signature `setValue(string)` and selector `[147, 160, 147, 82]`"]
#[derive(
Clone,
Debug,
Default,
Eq,
PartialEq,
ethers_contract :: EthCall,
ethers_contract :: EthDisplay,
)]
#[ethcall(name = "setValue", abi = "setValue(string)")]
pub struct SetValueCall {
pub value: String,
}
#[derive(Debug, Clone, PartialEq, Eq, ethers_contract :: EthAbiType)]
pub enum SimpleStorageCalls {
GetValue(GetValueCall),
SetValue(SetValueCall),
}
impl SimpleStorageCalls {
#[doc = r" Decodes the provided ABI encoded function arguments with the selected function name."]
pub fn decode(data: &[u8]) -> Result<Self, ethers_core::abi::Error> {
if let Ok(decoded) = <GetValueCall as ethers_contract::EthCall>::decode(data) {
return Ok(SimpleStorageCalls::GetValue(decoded));
}
if let Ok(decoded) = <SetValueCall as ethers_contract::EthCall>::decode(data) {
return Ok(SimpleStorageCalls::SetValue(decoded));
}
Err(ethers_core::abi::Error::InvalidData)
}
}
impl ::std::fmt::Display for SimpleStorageCalls {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match self {
SimpleStorageCalls::GetValue(element) => element.fmt(f),
SimpleStorageCalls::SetValue(element) => element.fmt(f),
}
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - feel free to merge whenever. Minor comments.
Function { | ||
name: function_call_name.clone(), | ||
inputs, | ||
outputs: vec![], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this not have any outputs / state mutability? What about view
functions for example? Maybe they can be omitted by default, but add a #[ethcall(return = "(uint256, string)"]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rn only inputs are supported, but we should extend on that on also support response types,
will follow up with this separately.
/// } | ||
/// | ||
/// #[derive(Debug, PartialEq, EthCall)] | ||
/// #[ethcall(name = "foo", abi = "foo(address,(address,string),string)")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to do the overriding here, or can it be automatically detected too for nested structs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is currently a limitation, because we don't know the ABI of the nested struct during macro expansion, and we need to know the param types for that type so we can generate the decode
function body.
To mitigate this we could think of introducing a nother trait looks like 👍
trait AbiType {
fn type_param() -> ParamType;
}
// Example impl
impl AbiType for bool {
fn type_param() -> ParamType {
ParamType::Bool
}
}
this would improve things in the EthEvent
and EthAbiType
macro as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think that connecting the native` types to ParamTypes makes sense. Surprised EthABI didn't have that in the first place.
/// A helper trait for types that represent all call input parameters of a specific function | ||
pub trait EthCall: Tokenizable + AbiDecode + Send + Sync { | ||
/// The name of the function | ||
fn function_name() -> Cow<'static, str>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the advantage of returning a Cow instead of a 'static str
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently none, I think, but I wasn't sure whether this also allows others to implement calls that construct the function name dynamically, since this is a type function, &'static str should be sufficient.
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
Motivation
Closes #507
Solution
EthCall
trait that works similar toEthEvent
EthCall
EthAbiType
work for enums with a single fieldPR Checklist