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(
53 &self,
54 name: &str,
55 data: &[u8],
56 validate: bool,
57 ) -> Result<Vec<DynSolValue>> {
58 self.get_from_name(name)?.abi_decode_input(data, validate).map_err(Into::into)
59 }
60
61 pub fn decode_input_with_selector(
63 &self,
64 selector: &Selector,
65 data: &[u8],
66 validate: bool,
67 ) -> Result<Vec<DynSolValue>> {
68 self.get_from_selector(selector)?.abi_decode_input(data, validate).map_err(Into::into)
69 }
70
71 pub fn decode_output(
79 &self,
80 name: &str,
81 data: &[u8],
82 validate: bool,
83 ) -> Result<Vec<DynSolValue>> {
84 self.get_from_name(name)?.abi_decode_output(data, validate).map_err(Into::into)
85 }
86
87 pub fn decode_output_with_selector(
89 &self,
90 selector: &Selector,
91 data: &[u8],
92 validate: bool,
93 ) -> Result<Vec<DynSolValue>> {
94 self.get_from_selector(selector)?.abi_decode_output(data, validate).map_err(Into::into)
95 }
96
97 pub const fn abi(&self) -> &JsonAbi {
99 &self.abi
100 }
101
102 pub fn into_abi(self) -> JsonAbi {
104 self.abi
105 }
106
107 pub(crate) fn get_from_name(&self, name: &str) -> Result<&Function> {
108 self.abi
109 .function(name)
110 .and_then(|r| r.first())
111 .ok_or_else(|| Error::UnknownFunction(name.to_string()))
112 }
113
114 pub(crate) fn get_from_selector(&self, selector: &Selector) -> Result<&Function> {
115 self.functions
116 .get(selector)
117 .map(|(name, index)| &self.abi.functions[name][*index])
118 .ok_or_else(|| Error::UnknownSelector(*selector))
119 }
120
121 pub const fn connect<P, N>(self, address: Address, provider: P) -> ContractInstance<P, N> {
123 ContractInstance::new(address, provider, self)
124 }
125}
126
127fn create_mapping<const N: usize, T, F>(
130 elements: &BTreeMap<String, Vec<T>>,
131 signature: F,
132) -> FbHashMap<N, (String, usize)>
133where
134 F: Fn(&T) -> FixedBytes<N> + Copy,
135{
136 elements
137 .iter()
138 .flat_map(|(name, sub_elements)| {
139 sub_elements
140 .iter()
141 .enumerate()
142 .map(move |(index, element)| (signature(element), (name.to_owned(), index)))
143 })
144 .collect()
145}