alloy_contract/
interface.rs1use crate::{ContractInstance, Error, Result};
2use alloy_dyn_abi::{DynSolValue, FunctionExt, JsonAbiExt};
3use alloy_json_abi::{Function, JsonAbi};
4use alloy_primitives::{
5 map::{FbHashMap, SelectorHashMap},
6 Address, FixedBytes, Selector,
7};
8use std::collections::BTreeMap;
9
10#[derive(Clone, Debug)]
12pub struct Interface {
13 abi: JsonAbi,
14 functions: SelectorHashMap<(String, usize)>,
15}
16
17impl Interface {
19 pub fn new(abi: JsonAbi) -> Self {
21 let functions = create_mapping(&abi.functions, Function::selector);
22 Self { abi, functions }
23 }
24
25 pub fn encode_input(&self, name: &str, args: &[DynSolValue]) -> Result<Vec<u8>> {
33 self.get_from_name(name)?.abi_encode_input(args).map_err(Into::into)
34 }
35
36 pub fn encode_input_with_selector(
39 &self,
40 selector: &Selector,
41 args: &[DynSolValue],
42 ) -> Result<Vec<u8>> {
43 self.get_from_selector(selector)?.abi_encode_input(args).map_err(Into::into)
44 }
45
46 pub fn decode_input(&self, name: &str, data: &[u8]) -> Result<Vec<DynSolValue>> {
53 self.get_from_name(name)?.abi_decode_input(data).map_err(Into::into)
54 }
55
56 pub fn decode_input_with_selector(
58 &self,
59 selector: &Selector,
60 data: &[u8],
61 ) -> Result<Vec<DynSolValue>> {
62 self.get_from_selector(selector)?.abi_decode_input(data).map_err(Into::into)
63 }
64
65 pub fn decode_output(&self, name: &str, data: &[u8]) -> Result<Vec<DynSolValue>> {
73 self.get_from_name(name)?.abi_decode_output(data).map_err(Into::into)
74 }
75
76 pub fn decode_output_with_selector(
78 &self,
79 selector: &Selector,
80 data: &[u8],
81 ) -> Result<Vec<DynSolValue>> {
82 self.get_from_selector(selector)?.abi_decode_output(data).map_err(Into::into)
83 }
84
85 pub const fn abi(&self) -> &JsonAbi {
87 &self.abi
88 }
89
90 pub fn into_abi(self) -> JsonAbi {
92 self.abi
93 }
94
95 pub(crate) fn get_from_name(&self, name: &str) -> Result<&Function> {
96 self.abi
97 .function(name)
98 .and_then(|r| r.first())
99 .ok_or_else(|| Error::UnknownFunction(name.to_string()))
100 }
101
102 pub(crate) fn get_from_selector(&self, selector: &Selector) -> Result<&Function> {
103 self.functions
104 .get(selector)
105 .map(|(name, index)| &self.abi.functions[name][*index])
106 .ok_or_else(|| Error::UnknownSelector(*selector))
107 }
108
109 pub const fn connect<P, N>(self, address: Address, provider: P) -> ContractInstance<P, N> {
111 ContractInstance::new(address, provider, self)
112 }
113}
114
115fn create_mapping<const N: usize, T, F>(
118 elements: &BTreeMap<String, Vec<T>>,
119 signature: F,
120) -> FbHashMap<N, (String, usize)>
121where
122 F: Fn(&T) -> FixedBytes<N> + Copy,
123{
124 elements
125 .iter()
126 .flat_map(|(name, sub_elements)| {
127 sub_elements
128 .iter()
129 .enumerate()
130 .map(move |(index, element)| (signature(element), (name.to_owned(), index)))
131 })
132 .collect()
133}