alloy_dyn_abi/dynamic/
call.rsuse crate::{DynSolType, DynSolValue, Error, Result};
use alloy_primitives::Selector;
use alloy_sol_types::abi::Decoder;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DynSolCall {
selector: Selector,
parameters: Vec<DynSolType>,
method: Option<String>,
returns: DynSolReturns,
}
impl DynSolCall {
pub const fn new(
selector: Selector,
parameters: Vec<DynSolType>,
method: Option<String>,
returns: DynSolReturns,
) -> Self {
Self { selector, parameters, method, returns }
}
pub const fn selector(&self) -> Selector {
self.selector
}
pub fn types(&self) -> &[DynSolType] {
&self.parameters
}
pub fn method(&self) -> Option<&str> {
self.method.as_deref()
}
pub fn abi_encode_input(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
encode_typeck(&self.parameters, values).map(prefix_selector(self.selector))
}
pub fn abi_encode_input_raw(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
encode_typeck(&self.parameters, values)
}
pub fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.parameters, validate)
}
pub fn abi_encode_output(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
self.returns.abi_encode_output(values)
}
pub fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
self.returns.abi_decode_output(data, validate)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DynSolReturns(Vec<DynSolType>);
impl From<Vec<DynSolType>> for DynSolReturns {
fn from(types: Vec<DynSolType>) -> Self {
Self(types)
}
}
impl From<DynSolReturns> for Vec<DynSolType> {
fn from(returns: DynSolReturns) -> Self {
returns.0
}
}
impl DynSolReturns {
pub const fn new(types: Vec<DynSolType>) -> Self {
Self(types)
}
pub fn types(&self) -> &[DynSolType] {
&self.0
}
pub fn abi_encode_output(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
encode_typeck(self.types(), values)
}
pub fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, self.types(), validate)
}
}
#[inline]
pub(crate) fn prefix_selector(selector: Selector) -> impl FnOnce(Vec<u8>) -> Vec<u8> {
move |data| {
let mut new = Vec::with_capacity(data.len() + 4);
new.extend_from_slice(&selector[..]);
new.extend_from_slice(&data[..]);
new
}
}
pub(crate) fn encode_typeck(tys: &[DynSolType], values: &[DynSolValue]) -> Result<Vec<u8>> {
if values.len() != tys.len() {
return Err(Error::EncodeLengthMismatch { expected: tys.len(), actual: values.len() });
}
for (value, ty) in core::iter::zip(values, tys) {
if !ty.matches(value) {
return Err(Error::TypeMismatch {
expected: ty.sol_type_name().into_owned(),
actual: value.sol_type_name().unwrap_or_else(|| "<none>".into()).into_owned(),
});
}
}
Ok(abi_encode(values))
}
#[inline]
pub(crate) fn abi_encode(values: &[DynSolValue]) -> Vec<u8> {
DynSolValue::encode_seq(values)
}
pub(crate) fn abi_decode(
data: &[u8],
tys: &[DynSolType],
validate: bool,
) -> Result<Vec<DynSolValue>> {
let mut values = Vec::with_capacity(tys.len());
let mut decoder = Decoder::new(data, validate);
for ty in tys {
let value = ty.abi_decode_inner(&mut decoder, crate::DynToken::decode_single_populate)?;
values.push(value);
}
Ok(values)
}