starknet_rust_providers/sequencer/models/
transaction_request.rs

1use serde::{Deserialize, Serialize, Serializer};
2use serde_with::serde_as;
3use starknet_rust_core::{
4    serde::unsigned_field_element::{UfeHex, UfeHexOption},
5    types::Felt,
6};
7use std::sync::Arc;
8
9use super::{
10    contract::{CompressedLegacyContractClass, CompressedSierraClass},
11    serde_impls::u64_hex,
12    transaction::{DataAvailabilityMode, ResourceBoundsMapping},
13    L1Address,
14};
15
16/// 2 ^ 128 + 1
17const QUERY_VERSION_ONE: Felt = Felt::from_raw([
18    576460752142433776,
19    18446744073709551584,
20    17407,
21    18446744073700081633,
22]);
23
24/// 2 ^ 128 + 2
25const QUERY_VERSION_TWO: Felt = Felt::from_raw([
26    576460752142433232,
27    18446744073709551584,
28    17407,
29    18446744073700081601,
30]);
31
32/// 2 ^ 128 + 3
33const QUERY_VERSION_THREE: Felt = Felt::from_raw([
34    576460752142432688,
35    18446744073709551584,
36    17407,
37    18446744073700081569,
38]);
39
40#[serde_as]
41#[derive(Debug, Deserialize)]
42#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
43pub struct AddTransactionResult {
44    pub code: AddTransactionResultCode,
45    #[serde_as(as = "UfeHex")]
46    pub transaction_hash: Felt,
47    #[serde(default)]
48    #[serde_as(as = "UfeHexOption")]
49    pub address: Option<Felt>,
50    #[serde(default)]
51    #[serde_as(as = "UfeHexOption")]
52    pub class_hash: Option<Felt>,
53}
54
55#[derive(Debug, PartialEq, Eq, Deserialize)]
56#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))]
57pub enum AddTransactionResultCode {
58    #[serde(rename = "TRANSACTION_RECEIVED")]
59    TransactionReceived,
60}
61
62#[derive(Debug, Serialize)]
63#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
64pub enum TransactionRequest {
65    Declare(DeclareTransaction),
66    InvokeFunction(InvokeFunctionTransaction),
67    DeployAccount(DeployAccountTransaction),
68}
69
70#[derive(Debug, Serialize)]
71#[serde(untagged)]
72pub enum DeclareTransaction {
73    V1(DeclareV1Transaction),
74    V2(DeclareV2Transaction),
75    V3(DeclareV3Transaction),
76}
77
78#[derive(Debug)]
79pub struct DeclareV1Transaction {
80    pub contract_class: Arc<CompressedLegacyContractClass>,
81    /// The address of the account contract sending the declaration transaction.
82    pub sender_address: Felt,
83    /// The maximal fee to be paid in Wei for declaring a contract class.
84    pub max_fee: Felt,
85    /// Additional information given by the caller that represents the signature of the transaction.
86    pub signature: Vec<Felt>,
87    /// A sequential integer used to distinguish between transactions and order them.
88    pub nonce: Felt,
89    pub is_query: bool,
90}
91
92#[derive(Debug)]
93pub struct DeclareV2Transaction {
94    pub contract_class: Arc<CompressedSierraClass>,
95    /// Hash of the compiled class obtained by running `starknet-sierra-compile` on the Sierra
96    /// class. This is required because at the moment, Sierra compilation is not proven, allowing
97    /// the sequencer to run arbitrary code if this is not signed. It's expected that in the future
98    /// this will no longer be required.
99    pub compiled_class_hash: Felt,
100    /// The address of the account contract sending the declaration transaction.
101    pub sender_address: Felt,
102    /// The maximal fee to be paid in Wei for declaring a contract class.
103    pub max_fee: Felt,
104    /// Additional information given by the caller that represents the signature of the transaction.
105    pub signature: Vec<Felt>,
106    /// A sequential integer used to distinguish between transactions and order them.
107    pub nonce: Felt,
108    pub is_query: bool,
109}
110
111#[derive(Debug)]
112pub struct DeclareV3Transaction {
113    pub contract_class: Arc<CompressedSierraClass>,
114    /// Hash of the compiled class obtained by running `starknet-sierra-compile` on the Sierra
115    /// class. This is required because at the moment, Sierra compilation is not proven, allowing
116    /// the sequencer to run arbitrary code if this is not signed. It's expected that in the future
117    /// this will no longer be required.
118    pub compiled_class_hash: Felt,
119    /// The address of the account contract sending the declaration transaction.
120    pub sender_address: Felt,
121    /// Additional information given by the caller that represents the signature of the transaction.
122    pub signature: Vec<Felt>,
123    /// A sequential integer used to distinguish between transactions and order them.
124    pub nonce: Felt,
125    pub nonce_data_availability_mode: DataAvailabilityMode,
126    pub fee_data_availability_mode: DataAvailabilityMode,
127    pub resource_bounds: ResourceBoundsMapping,
128    pub tip: u64,
129    pub paymaster_data: Vec<Felt>,
130    pub account_deployment_data: Vec<Felt>,
131    pub is_query: bool,
132}
133
134#[derive(Debug, Serialize)]
135#[serde(untagged)]
136pub enum InvokeFunctionTransaction {
137    V1(InvokeFunctionV1Transaction),
138    V3(InvokeFunctionV3Transaction),
139}
140
141#[derive(Debug)]
142pub struct InvokeFunctionV1Transaction {
143    pub sender_address: Felt,
144    pub calldata: Vec<Felt>,
145    pub signature: Vec<Felt>,
146    pub max_fee: Felt,
147    pub nonce: Felt,
148    pub is_query: bool,
149}
150
151#[derive(Debug)]
152pub struct InvokeFunctionV3Transaction {
153    pub sender_address: Felt,
154    pub calldata: Vec<Felt>,
155    pub signature: Vec<Felt>,
156    pub nonce: Felt,
157    pub nonce_data_availability_mode: DataAvailabilityMode,
158    pub fee_data_availability_mode: DataAvailabilityMode,
159    pub resource_bounds: ResourceBoundsMapping,
160    pub tip: u64,
161    pub paymaster_data: Vec<Felt>,
162    pub account_deployment_data: Vec<Felt>,
163    pub is_query: bool,
164}
165
166#[derive(Debug, Serialize)]
167#[serde(untagged)]
168pub enum DeployAccountTransaction {
169    V1(DeployAccountV1Transaction),
170    V3(DeployAccountV3Transaction),
171}
172
173#[derive(Debug)]
174pub struct DeployAccountV1Transaction {
175    pub class_hash: Felt,
176    pub contract_address_salt: Felt,
177    pub constructor_calldata: Vec<Felt>,
178    // The maximal fee to be paid in Wei for executing the transaction.
179    pub max_fee: Felt,
180    // The signature of the transaction.
181    pub signature: Vec<Felt>,
182    // The nonce of the transaction.
183    pub nonce: Felt,
184    pub is_query: bool,
185}
186
187#[derive(Debug)]
188pub struct DeployAccountV3Transaction {
189    pub class_hash: Felt,
190    pub contract_address_salt: Felt,
191    pub constructor_calldata: Vec<Felt>,
192    // The signature of the transaction.
193    pub signature: Vec<Felt>,
194    // The nonce of the transaction.
195    pub nonce: Felt,
196    pub nonce_data_availability_mode: DataAvailabilityMode,
197    pub fee_data_availability_mode: DataAvailabilityMode,
198    pub resource_bounds: ResourceBoundsMapping,
199    pub tip: u64,
200    pub paymaster_data: Vec<Felt>,
201    pub is_query: bool,
202}
203
204impl Serialize for DeclareV1Transaction {
205    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
206    where
207        S: Serializer,
208    {
209        #[serde_as]
210        #[derive(Serialize)]
211        struct Versioned<'a> {
212            #[serde_as(as = "UfeHex")]
213            version: Felt,
214            contract_class: &'a CompressedLegacyContractClass,
215            #[serde_as(as = "UfeHex")]
216            sender_address: &'a Felt,
217            #[serde_as(as = "UfeHex")]
218            max_fee: &'a Felt,
219            signature: &'a Vec<Felt>,
220            #[serde_as(as = "UfeHex")]
221            nonce: &'a Felt,
222        }
223
224        let versioned = Versioned {
225            version: if self.is_query {
226                QUERY_VERSION_ONE
227            } else {
228                Felt::ONE
229            },
230            contract_class: &self.contract_class,
231            sender_address: &self.sender_address,
232            max_fee: &self.max_fee,
233            signature: &self.signature,
234            nonce: &self.nonce,
235        };
236
237        Versioned::serialize(&versioned, serializer)
238    }
239}
240
241impl Serialize for DeclareV2Transaction {
242    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
243    where
244        S: Serializer,
245    {
246        #[serde_as]
247        #[derive(Serialize)]
248        struct Versioned<'a> {
249            #[serde_as(as = "UfeHex")]
250            version: Felt,
251            contract_class: &'a CompressedSierraClass,
252            #[serde_as(as = "UfeHex")]
253            compiled_class_hash: &'a Felt,
254            #[serde_as(as = "UfeHex")]
255            sender_address: &'a Felt,
256            #[serde_as(as = "UfeHex")]
257            max_fee: &'a Felt,
258            signature: &'a Vec<Felt>,
259            #[serde_as(as = "UfeHex")]
260            nonce: &'a Felt,
261        }
262
263        let versioned = Versioned {
264            version: if self.is_query {
265                QUERY_VERSION_TWO
266            } else {
267                Felt::TWO
268            },
269            contract_class: &self.contract_class,
270            compiled_class_hash: &self.compiled_class_hash,
271            sender_address: &self.sender_address,
272            max_fee: &self.max_fee,
273            signature: &self.signature,
274            nonce: &self.nonce,
275        };
276
277        Versioned::serialize(&versioned, serializer)
278    }
279}
280
281impl Serialize for DeclareV3Transaction {
282    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
283    where
284        S: Serializer,
285    {
286        #[serde_as]
287        #[derive(Serialize)]
288        struct Versioned<'a> {
289            #[serde_as(as = "UfeHex")]
290            version: Felt,
291            contract_class: &'a CompressedSierraClass,
292            #[serde_as(as = "UfeHex")]
293            compiled_class_hash: &'a Felt,
294            #[serde_as(as = "UfeHex")]
295            sender_address: &'a Felt,
296            #[serde_as(as = "Vec<UfeHex>")]
297            signature: &'a Vec<Felt>,
298            #[serde_as(as = "UfeHex")]
299            nonce: &'a Felt,
300            nonce_data_availability_mode: &'a DataAvailabilityMode,
301            fee_data_availability_mode: &'a DataAvailabilityMode,
302            resource_bounds: &'a ResourceBoundsMapping,
303            #[serde(with = "u64_hex")]
304            tip: &'a u64,
305            #[serde_as(as = "Vec<UfeHex>")]
306            paymaster_data: &'a Vec<Felt>,
307            #[serde_as(as = "Vec<UfeHex>")]
308            account_deployment_data: &'a Vec<Felt>,
309        }
310
311        let versioned = Versioned {
312            version: if self.is_query {
313                QUERY_VERSION_THREE
314            } else {
315                Felt::THREE
316            },
317            contract_class: &self.contract_class,
318            compiled_class_hash: &self.compiled_class_hash,
319            sender_address: &self.sender_address,
320            signature: &self.signature,
321            nonce: &self.nonce,
322            nonce_data_availability_mode: &self.nonce_data_availability_mode,
323            fee_data_availability_mode: &self.fee_data_availability_mode,
324            resource_bounds: &self.resource_bounds,
325            tip: &self.tip,
326            paymaster_data: &self.paymaster_data,
327            account_deployment_data: &self.account_deployment_data,
328        };
329
330        Versioned::serialize(&versioned, serializer)
331    }
332}
333
334impl Serialize for InvokeFunctionV1Transaction {
335    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
336    where
337        S: Serializer,
338    {
339        #[serde_as]
340        #[derive(Serialize)]
341        struct Versioned<'a> {
342            #[serde_as(as = "UfeHex")]
343            version: Felt,
344            #[serde_as(as = "UfeHex")]
345            sender_address: &'a Felt,
346            calldata: &'a Vec<Felt>,
347            signature: &'a Vec<Felt>,
348            #[serde_as(as = "UfeHex")]
349            max_fee: &'a Felt,
350            #[serde_as(as = "UfeHex")]
351            nonce: &'a Felt,
352        }
353
354        let versioned = Versioned {
355            version: if self.is_query {
356                QUERY_VERSION_ONE
357            } else {
358                Felt::ONE
359            },
360            sender_address: &self.sender_address,
361            calldata: &self.calldata,
362            signature: &self.signature,
363            max_fee: &self.max_fee,
364            nonce: &self.nonce,
365        };
366
367        Versioned::serialize(&versioned, serializer)
368    }
369}
370
371impl Serialize for InvokeFunctionV3Transaction {
372    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
373    where
374        S: Serializer,
375    {
376        #[serde_as]
377        #[derive(Serialize)]
378        struct Versioned<'a> {
379            #[serde_as(as = "UfeHex")]
380            version: Felt,
381            #[serde_as(as = "UfeHex")]
382            sender_address: &'a Felt,
383            calldata: &'a Vec<Felt>,
384            #[serde_as(as = "Vec<UfeHex>")]
385            signature: &'a Vec<Felt>,
386            #[serde_as(as = "UfeHex")]
387            nonce: &'a Felt,
388            nonce_data_availability_mode: &'a DataAvailabilityMode,
389            fee_data_availability_mode: &'a DataAvailabilityMode,
390            resource_bounds: &'a ResourceBoundsMapping,
391            #[serde(with = "u64_hex")]
392            tip: &'a u64,
393            #[serde_as(as = "Vec<UfeHex>")]
394            paymaster_data: &'a Vec<Felt>,
395            #[serde_as(as = "Vec<UfeHex>")]
396            account_deployment_data: &'a Vec<Felt>,
397        }
398
399        let versioned = Versioned {
400            version: if self.is_query {
401                QUERY_VERSION_THREE
402            } else {
403                Felt::THREE
404            },
405            sender_address: &self.sender_address,
406            calldata: &self.calldata,
407            signature: &self.signature,
408            nonce: &self.nonce,
409            nonce_data_availability_mode: &self.nonce_data_availability_mode,
410            fee_data_availability_mode: &self.fee_data_availability_mode,
411            resource_bounds: &self.resource_bounds,
412            tip: &self.tip,
413            paymaster_data: &self.paymaster_data,
414            account_deployment_data: &self.account_deployment_data,
415        };
416
417        Versioned::serialize(&versioned, serializer)
418    }
419}
420
421impl Serialize for DeployAccountV1Transaction {
422    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
423    where
424        S: Serializer,
425    {
426        #[serde_as]
427        #[derive(Serialize)]
428        struct Versioned<'a> {
429            #[serde_as(as = "UfeHex")]
430            version: Felt,
431            #[serde_as(as = "UfeHex")]
432            class_hash: &'a Felt,
433            #[serde_as(as = "UfeHex")]
434            contract_address_salt: &'a Felt,
435            constructor_calldata: &'a Vec<Felt>,
436            #[serde_as(as = "UfeHex")]
437            max_fee: &'a Felt,
438            signature: &'a Vec<Felt>,
439            #[serde_as(as = "UfeHex")]
440            nonce: &'a Felt,
441        }
442
443        let versioned = Versioned {
444            version: if self.is_query {
445                QUERY_VERSION_ONE
446            } else {
447                Felt::ONE
448            },
449            class_hash: &self.class_hash,
450            contract_address_salt: &self.contract_address_salt,
451            constructor_calldata: &self.constructor_calldata,
452            max_fee: &self.max_fee,
453            signature: &self.signature,
454            nonce: &self.nonce,
455        };
456
457        Versioned::serialize(&versioned, serializer)
458    }
459}
460
461impl Serialize for DeployAccountV3Transaction {
462    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
463    where
464        S: Serializer,
465    {
466        #[serde_as]
467        #[derive(Serialize)]
468        struct Versioned<'a> {
469            #[serde_as(as = "UfeHex")]
470            version: Felt,
471            #[serde_as(as = "UfeHex")]
472            class_hash: &'a Felt,
473            #[serde_as(as = "UfeHex")]
474            contract_address_salt: &'a Felt,
475            #[serde_as(as = "Vec<UfeHex>")]
476            constructor_calldata: &'a Vec<Felt>,
477            #[serde_as(as = "Vec<UfeHex>")]
478            signature: &'a Vec<Felt>,
479            #[serde_as(as = "UfeHex")]
480            nonce: &'a Felt,
481            nonce_data_availability_mode: &'a DataAvailabilityMode,
482            fee_data_availability_mode: &'a DataAvailabilityMode,
483            resource_bounds: &'a ResourceBoundsMapping,
484            #[serde(with = "u64_hex")]
485            tip: &'a u64,
486            #[serde_as(as = "Vec<UfeHex>")]
487            paymaster_data: &'a Vec<Felt>,
488        }
489
490        let versioned = Versioned {
491            version: if self.is_query {
492                QUERY_VERSION_THREE
493            } else {
494                Felt::THREE
495            },
496            class_hash: &self.class_hash,
497            contract_address_salt: &self.contract_address_salt,
498            constructor_calldata: &self.constructor_calldata,
499            signature: &self.signature,
500            nonce: &self.nonce,
501            nonce_data_availability_mode: &self.nonce_data_availability_mode,
502            fee_data_availability_mode: &self.fee_data_availability_mode,
503            resource_bounds: &self.resource_bounds,
504            tip: &self.tip,
505            paymaster_data: &self.paymaster_data,
506        };
507
508        Versioned::serialize(&versioned, serializer)
509    }
510}
511
512fn l1_addr_as_dec<S>(value: &L1Address, serializer: S) -> Result<S::Ok, S::Error>
513where
514    S: Serializer,
515{
516    let mut buffer = [0u8; 32];
517    buffer[12..].copy_from_slice(&value.0);
518
519    // Unwrapping is safe here as it's never out of range
520    let addr_in_felt = Felt::from_bytes_be(&buffer);
521
522    serializer.serialize_str(&addr_in_felt.to_string())
523}