#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(not(feature = "std"))]
use crate::no_std_prelude::*;
use crate::{
decode, encode, signature::short_signature, Bytes, Error, Param, ParamType, Result, StateMutability, Token,
};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub struct Function {
#[cfg_attr(feature = "serde", serde(deserialize_with = "crate::util::sanitize_name::deserialize"))]
pub name: String,
pub inputs: Vec<Param>,
pub outputs: Vec<Param>,
#[deprecated(note = "The constant attribute was removed in Solidity 0.5.0 and has been \
replaced with stateMutability.")]
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub constant: Option<bool>,
#[cfg_attr(feature = "serde", serde(rename = "stateMutability", default))]
pub state_mutability: StateMutability,
}
impl Function {
fn input_param_types(&self) -> Vec<ParamType> {
self.inputs.iter().map(|p| p.kind.clone()).collect()
}
fn output_param_types(&self) -> Vec<ParamType> {
self.outputs.iter().map(|p| p.kind.clone()).collect()
}
pub fn encode_input(&self, tokens: &[Token]) -> Result<Bytes> {
let params = self.input_param_types();
if !Token::types_check(tokens, ¶ms) {
return Err(Error::InvalidData);
}
let signed = short_signature(&self.name, ¶ms).to_vec();
let encoded = encode(tokens);
Ok(signed.into_iter().chain(encoded.into_iter()).collect())
}
pub fn short_signature(&self) -> [u8; 4] {
let params = self.input_param_types();
short_signature(&self.name, ¶ms)
}
pub fn decode_output(&self, data: &[u8]) -> Result<Vec<Token>> {
decode(&self.output_param_types(), data)
}
pub fn decode_input(&self, data: &[u8]) -> Result<Vec<Token>> {
decode(&self.input_param_types(), data)
}
pub fn signature(&self) -> String {
let inputs = self.inputs.iter().map(|p| p.kind.to_string()).collect::<Vec<_>>().join(",");
let outputs = self.outputs.iter().map(|p| p.kind.to_string()).collect::<Vec<_>>().join(",");
match (inputs.len(), outputs.len()) {
(_, 0) => format!("{}({inputs})", self.name),
(_, _) => format!("{}({inputs}):({outputs})", self.name),
}
}
}
#[cfg(test)]
mod tests {
use hex_literal::hex;
#[cfg(not(feature = "std"))]
use crate::no_std_prelude::*;
use crate::{Function, Param, ParamType, StateMutability, Token};
#[test]
fn test_function_encode_call() {
#[allow(deprecated)]
let func = Function {
name: "baz".to_owned(),
inputs: vec![
Param { name: "a".to_owned(), kind: ParamType::Uint(32), internal_type: None },
Param { name: "b".to_owned(), kind: ParamType::Bool, internal_type: None },
],
outputs: vec![],
constant: None,
state_mutability: StateMutability::Payable,
};
let mut uint = [0u8; 32];
uint[31] = 69;
let encoded = func.encode_input(&[Token::Uint(uint.into()), Token::Bool(true)]).unwrap();
let expected = hex!("cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001").to_vec();
assert_eq!(encoded, expected);
let expected_sig = hex!("cdcd77c0").to_vec();
assert_eq!(func.short_signature().to_vec(), expected_sig);
}
}