cairo_lang_starknet_classes/
abi.rs

1use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
2use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
3use serde::{Deserialize, Serialize};
4
5/// Contract ABI.
6#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(transparent)]
8pub struct Contract {
9    items: OrderedHashSet<Item>,
10}
11impl Contract {
12    pub fn from_items(items: OrderedHashSet<Item>) -> Self {
13        Self { items }
14    }
15
16    pub fn json(&self) -> String {
17        serde_json::to_string_pretty(&self).unwrap()
18    }
19
20    /// Validates the ABI entry point counts match the expected counts.
21    pub fn sanity_check(
22        &self,
23        expected_external_count: usize,
24        expected_l1_handler_count: usize,
25        expected_constructor_count: usize,
26    ) {
27        let trait_fn_count: UnorderedHashMap<_, _> = self
28            .items
29            .iter()
30            .filter_map(|item| {
31                let Item::Interface(imp) = item else {
32                    return None;
33                };
34                Some((imp.name.clone(), imp.items.len()))
35            })
36            .collect();
37        let mut external_count = 0;
38        let mut l1_handler_count = 0;
39        let mut constructor_count = 0;
40        for item in &self.items {
41            match item {
42                Item::Function(_) => external_count += 1,
43                Item::L1Handler(_) => l1_handler_count += 1,
44                Item::Constructor(_) => constructor_count += 1,
45                Item::Impl(imp) => {
46                    external_count += trait_fn_count.get(&imp.interface_name).unwrap_or_else(|| {
47                        panic!("Interface `{}` not found in ABI.", imp.interface_name)
48                    })
49                }
50                _ => {}
51            }
52        }
53        assert_eq!(external_count, expected_external_count);
54        assert_eq!(l1_handler_count, expected_l1_handler_count);
55        assert_eq!(constructor_count, expected_constructor_count);
56    }
57}
58
59impl IntoIterator for Contract {
60    type Item = Item;
61    type IntoIter = <OrderedHashSet<Item> as IntoIterator>::IntoIter;
62
63    fn into_iter(self) -> Self::IntoIter {
64        self.items.into_iter()
65    }
66}
67
68/// Enum of contract item ABIs.
69#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
70#[serde(tag = "type")]
71pub enum Item {
72    #[serde(rename = "function")]
73    Function(Function),
74    #[serde(rename = "constructor")]
75    Constructor(Constructor),
76    #[serde(rename = "l1_handler")]
77    L1Handler(L1Handler),
78    #[serde(rename = "event")]
79    Event(Event),
80    #[serde(rename = "struct")]
81    Struct(Struct),
82    #[serde(rename = "enum")]
83    Enum(Enum),
84    #[serde(rename = "interface")]
85    Interface(Interface),
86    #[serde(rename = "impl")]
87    Impl(Imp),
88}
89
90/// Contract interface ABI.
91#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
92pub struct Interface {
93    pub name: String,
94    pub items: Vec<Item>,
95}
96
97/// Contract impl ABI.
98#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
99pub struct Imp {
100    pub name: String,
101    pub interface_name: String,
102}
103
104#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
105pub enum StateMutability {
106    #[serde(rename = "external")]
107    External,
108    #[serde(rename = "view")]
109    View,
110}
111
112/// Contract function ABI.
113#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
114pub struct Function {
115    pub name: String,
116    pub inputs: Vec<Input>,
117
118    // TODO(ilya): Should the output be a vector or a single type?
119    pub outputs: Vec<Output>,
120    pub state_mutability: StateMutability,
121}
122
123/// Contract constructor ABI.
124#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
125pub struct Constructor {
126    pub name: String,
127    pub inputs: Vec<Input>,
128}
129
130/// Contract L1 handler ABI.
131#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
132pub struct L1Handler {
133    pub name: String,
134    pub inputs: Vec<Input>,
135
136    // TODO(ilya): Should the output be a vector or a single type?
137    pub outputs: Vec<Output>,
138    pub state_mutability: StateMutability,
139}
140
141/// Contract event.
142#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
143pub struct Event {
144    pub name: String,
145    #[serde(flatten)]
146    pub kind: EventKind,
147}
148
149/// Contract event kind.
150#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
151#[serde(tag = "kind")]
152pub enum EventKind {
153    #[serde(rename = "struct")]
154    Struct { members: Vec<EventField> },
155    #[serde(rename = "enum")]
156    Enum { variants: Vec<EventField> },
157}
158
159/// Contract event field (member/variant).
160#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
161pub struct EventField {
162    pub name: String,
163    #[serde(rename = "type")]
164    pub ty: String,
165    pub kind: EventFieldKind,
166}
167
168/// Describes how to serialize the event's field.
169#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
170pub enum EventFieldKind {
171    // Serialize to `keys` using `Serde`.
172    #[serde(rename = "key")]
173    KeySerde,
174    // Serialize to `data` using `Serde`.
175    #[serde(rename = "data")]
176    DataSerde,
177    // Serialize as a nested event.
178    #[serde(rename = "nested")]
179    Nested,
180    // Serialize as a flat event.
181    #[serde(rename = "flat")]
182    Flat,
183}
184
185/// Function input ABI.
186#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
187pub struct Input {
188    pub name: String,
189    #[serde(rename = "type")]
190    pub ty: String,
191}
192
193/// Function Output ABI.
194#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
195pub struct Output {
196    #[serde(rename = "type")]
197    pub ty: String,
198}
199
200/// Struct ABI.
201#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
202pub struct Struct {
203    pub name: String,
204    pub members: Vec<StructMember>,
205}
206
207/// Struct member.
208#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
209pub struct StructMember {
210    pub name: String,
211    #[serde(rename = "type")]
212    pub ty: String,
213}
214
215/// Enum ABI.
216#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
217pub struct Enum {
218    pub name: String,
219    pub variants: Vec<EnumVariant>,
220}
221
222/// Enum variant.
223#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
224pub struct EnumVariant {
225    pub name: String,
226    #[serde(rename = "type")]
227    pub ty: String,
228}