1use ethbind_gen::Generator;
2use ethbind_json::*;
3use heck::{ToSnakeCase, ToUpperCamelCase};
4use quote::{format_ident, quote};
5
6use crate::RustGenerator;
7
8impl Generator for RustGenerator {
9 fn begin<R: ethbind_gen::RuntimeBinder>(
10 &mut self,
11 _runtime_binder: &mut R,
12 name: &str,
13 ) -> anyhow::Result<()> {
14 self.new_contract(name);
15
16 Ok(())
17 }
18
19 fn end<R: ethbind_gen::RuntimeBinder>(
20 &mut self,
21 _runtime_binder: &mut R,
22 _name: &str,
23 ) -> anyhow::Result<()> {
24 Ok(())
25 }
26
27 fn finalize<R: ethbind_gen::RuntimeBinder>(
28 self,
29 runtime_binder: &mut R,
30 ) -> anyhow::Result<Vec<ethbind_gen::Contract>> {
31 let client_type = self.to_runtime_type_token_stream(runtime_binder, "rt_client")?;
32 let adress = self.to_runtime_type_token_stream(runtime_binder, "address")?;
33
34 let mut contracts = vec![];
35
36 for c in &self.contracts {
37 contracts.push(c.finalize(&client_type, &adress)?);
38 }
39
40 Ok(contracts)
41 }
42
43 fn generate_deploy<R: ethbind_gen::RuntimeBinder>(
44 &mut self,
45 runtime_binder: &mut R,
46 contructor: &Constructor,
47 deploy_bytes: &str,
48 ) -> anyhow::Result<()> {
49 let client_type = self.to_runtime_type_token_stream(runtime_binder, "rt_client")?;
50
51 let opts_type = self.to_runtime_type_token_stream(runtime_binder, "rt_opts")?;
52
53 let abi_encode = self.to_runtime_type_token_stream(runtime_binder, "rt_abi_serialize")?;
54
55 let error_type = self.to_runtime_type_token_stream(runtime_binder, "rt_error")?;
56
57 let generic_list = self.to_generic_list(runtime_binder, &contructor.inputs)?;
58
59 let param_list = self.to_param_list(runtime_binder, &contructor.inputs)?;
60
61 let where_clause_list = self.to_where_clause_list(runtime_binder, &contructor.inputs)?;
62
63 let try_into_list = self.to_try_into_list(runtime_binder, &contructor.inputs)?;
64
65 let abi_encode_list = self.to_abi_encode_list(runtime_binder, &contructor.inputs)?;
66
67 let fn_signature = contructor.signature();
68
69 self.current_contract().add_fn_token_stream(quote! {
70 pub async fn deploy_with<C, #(#generic_list,)* Ops>(client: C, #(#param_list,)* ops: Ops) -> std::result::Result<Self,#error_type>
71 where C: TryInto<#client_type>, C::Error: std::error::Error + Sync + Send + 'static,
72 Ops: TryInto<#opts_type>, Ops::Error: std::error::Error + Sync + Send + 'static,
73 #(#where_clause_list,)*
74 {
75 let mut client = client.try_into()?;
76 #(#try_into_list;)*
77 let ops = ops.try_into()?;
78
79 let outputs = #abi_encode(&#abi_encode_list)?;
80
81 let address = client.deploy_contract(#fn_signature, outputs,#deploy_bytes,ops).await?;
82
83 Ok(Self{ client, address })
84 }
85
86 pub async fn deploy<C, #(#generic_list,)* Ops>(client: C, #(#param_list,)*) -> std::result::Result<Self,#error_type>
87 where C: TryInto<#client_type>, C::Error: std::error::Error + Sync + Send + 'static,
88 #(#where_clause_list,)*
89 {
90 let mut client = client.try_into()?;
91 #(#try_into_list;)*
92
93 let outputs = #abi_encode(&#abi_encode_list)?;
94
95 let address = client.deploy_contract(#fn_signature, outputs,#deploy_bytes, Default::default()).await?;
96
97 Ok(Self{ client, address })
98 }
99 });
100
101 Ok(())
102 }
103
104 fn generate_error<R: ethbind_gen::RuntimeBinder>(
105 &mut self,
106 _runtime_binder: &mut R,
107 _error: &Error,
108 ) -> anyhow::Result<()> {
109 Ok(())
111 }
112
113 fn generate_event<R: ethbind_gen::RuntimeBinder>(
114 &mut self,
115 runtime_binder: &mut R,
116 event: &Event,
117 ) -> anyhow::Result<()> {
118 log::trace!("generate event {}", event.name);
119
120 let event_field_list = self.to_event_field_list(runtime_binder, &event.inputs)?;
121
122 let serialize_derive_macro =
123 self.to_runtime_type_token_stream(runtime_binder, "rt_serialize_derive")?;
124
125 let deserialize_derive_macro =
126 self.to_runtime_type_token_stream(runtime_binder, "rt_deserialize_derive")?;
127
128 let event_ident = format_ident!(
129 "{}{}",
130 self.current_contract().contract_name.to_upper_camel_case(),
131 event.name.to_upper_camel_case()
132 );
133
134 let abi_json = serde_json::to_string(event)?;
135
136 self.current_contract().add_event_token_stream(quote! {
137 #[derive(#serialize_derive_macro,#deserialize_derive_macro)]
138 pub struct #event_ident {
139 #(#event_field_list,)*
140 }
141
142 impl #event_ident {
143 pub fn abi_json() -> &'static str {
144 #abi_json
145 }
146 }
147 });
148
149 Ok(())
150 }
151
152 fn generate_fn<R: ethbind_gen::RuntimeBinder>(
153 &mut self,
154 runtime_binder: &mut R,
155 function: &Function,
156 ) -> anyhow::Result<()> {
157 log::trace!("genearte fn {}", function.name);
158
159 let opts_type = self.to_runtime_type_token_stream(runtime_binder, "rt_opts")?;
160
161 let error_type = self.to_runtime_type_token_stream(runtime_binder, "rt_error")?;
162
163 let abi_decode = self.to_runtime_type_token_stream(runtime_binder, "rt_abi_deserialize")?;
164
165 let abi_encode = self.to_runtime_type_token_stream(runtime_binder, "rt_abi_serialize")?;
166
167 let receipt_type = self.to_runtime_type_token_stream(runtime_binder, "rt_receipt")?;
168
169 let generic_list = self.to_generic_list(runtime_binder, &function.inputs)?;
170
171 let param_list = self.to_param_list(runtime_binder, &function.inputs)?;
172
173 let where_clause_list = self.to_where_clause_list(runtime_binder, &function.inputs)?;
174
175 let try_into_list = self.to_try_into_list(runtime_binder, &function.inputs)?;
176
177 let abi_encode_list = self.to_abi_encode_list(runtime_binder, &function.inputs)?;
178
179 let outputs_type = self.to_outputs_type(runtime_binder, &function.outputs)?;
180
181 let fn_ident = format_ident!("{}", function.name.to_snake_case());
182 let fn_with_ident = format_ident!("{}_with", function.name.to_snake_case());
183
184 let send_transaction = match function.state_mutability {
185 StateMutability::Pure | StateMutability::View => false,
186 _ => true,
187 };
188
189 let fn_signature = function.signature();
190
191 if send_transaction {
192 self.current_contract().add_fn_token_stream(quote! {
193 pub async fn #fn_with_ident<Ops, #(#generic_list,)* >(&self, #(#param_list,)* ops: Ops) -> std::result::Result<#receipt_type,#error_type>
194 where Ops: TryInto<#opts_type>, Ops::Error: std::error::Error + Sync + Send + 'static, #(#where_clause_list,)*
195 {
196 #(#try_into_list;)*
197 let ops = ops.try_into()?;
198
199 let outputs = #abi_encode(&#abi_encode_list)?;
200
201 self.client.send_raw_transaction(#fn_signature, &self.address, outputs,ops).await
202 }
203
204 pub async fn #fn_ident<#(#generic_list,)* >(&self, #(#param_list,)*) -> std::result::Result<#receipt_type,#error_type>
205 where #(#where_clause_list,)*
206 {
207 #(#try_into_list;)*
208
209 let outputs = #abi_encode(&#abi_encode_list)?;
210
211 self.client.send_raw_transaction(#fn_signature, &self.address, outputs, Default::default()).await
212 }
213 });
214 } else {
215 self.current_contract().add_fn_token_stream(quote! {
216 pub async fn #fn_ident<#(#generic_list,)* >(&self, #(#param_list,)*) -> std::result::Result<#outputs_type,#error_type>
217 where #(#where_clause_list,)*
218 {
219 #(#try_into_list;)*
220
221 let outputs = #abi_encode(&#abi_encode_list)?;
222
223 let inputs = self.client.eth_call(#fn_signature, &self.address, outputs).await?;
224
225 Ok(#abi_decode(inputs)?)
226 }
227 });
228 }
229
230 Ok(())
231 }
232}