starknet_core/types/
mod.rs

1use alloc::{string::*, vec::*};
2
3use serde::{Deserialize, Serialize};
4use serde_with::serde_as;
5
6use crate::serde::unsigned_field_element::UfeHex;
7
8pub use starknet_types_core::felt::*;
9
10mod conversions;
11
12mod serde_impls;
13
14/// SNIP-12 typed data.
15pub mod typed_data;
16pub use typed_data::TypedData;
17
18// TODO: better namespacing of exports?
19mod codegen;
20pub use codegen::{
21    BinaryNode, BlockHeader, BlockStatus, BlockTag, BlockWithReceipts, BlockWithTxHashes,
22    BlockWithTxs, BroadcastedDeclareTransaction, BroadcastedDeclareTransactionV3,
23    BroadcastedDeployAccountTransaction, BroadcastedDeployAccountTransactionV3,
24    BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV3, CallType,
25    CompressedLegacyContractClass, ContractErrorData, ContractLeafData, ContractStorageDiffItem,
26    ContractStorageKeys, ContractsProof, DataAvailabilityMode, DeclareTransactionReceipt,
27    DeclareTransactionTrace, DeclareTransactionV0, DeclareTransactionV0Content,
28    DeclareTransactionV1, DeclareTransactionV1Content, DeclareTransactionV2,
29    DeclareTransactionV2Content, DeclareTransactionV3, DeclareTransactionV3Content,
30    DeclaredClassItem, DeployAccountTransactionReceipt, DeployAccountTransactionTrace,
31    DeployAccountTransactionV1, DeployAccountTransactionV1Content, DeployAccountTransactionV3,
32    DeployAccountTransactionV3Content, DeployTransaction, DeployTransactionContent,
33    DeployTransactionReceipt, DeployedContractItem, EdgeNode, EmittedEvent,
34    EmittedEventWithFinality, EntryPointType, EntryPointsByType, Event, EventFilter,
35    EventFilterWithPage, EventsChunk, ExecutionResources, FeeEstimate, FeePayment,
36    FlattenedSierraClass, FunctionCall, FunctionInvocation, FunctionStateMutability, GlobalRoots,
37    InnerCallExecutionResources, InnerContractExecutionError, InvokeTransactionReceipt,
38    InvokeTransactionTrace, InvokeTransactionV0, InvokeTransactionV0Content, InvokeTransactionV1,
39    InvokeTransactionV1Content, InvokeTransactionV3, InvokeTransactionV3Content,
40    L1DataAvailabilityMode, L1HandlerTransaction, L1HandlerTransactionContent,
41    L1HandlerTransactionReceipt, L1HandlerTransactionTrace, L2TransactionFinalityStatus,
42    L2TransactionStatus, LegacyContractEntryPoint, LegacyEntryPointsByType, LegacyEventAbiEntry,
43    LegacyEventAbiType, LegacyFunctionAbiEntry, LegacyFunctionAbiType, LegacyStructAbiEntry,
44    LegacyStructAbiType, LegacyStructMember, LegacyTypedParameter, MessageFeeEstimate, MsgFromL1,
45    MsgToL1, NewTransactionStatus, NoTraceAvailableErrorData, NonceUpdate, OrderedEvent,
46    OrderedMessage, PreConfirmedBlockWithReceipts, PreConfirmedBlockWithTxHashes,
47    PreConfirmedBlockWithTxs, PreConfirmedStateUpdate, PriceUnit, ReorgData, ReplacedClassItem,
48    ResourceBounds, ResourceBoundsMapping, ResourcePrice, ResultPageRequest, RevertedInvocation,
49    SequencerTransactionStatus, SierraEntryPoint, SimulatedTransaction, SimulationFlag,
50    SimulationFlagForEstimateFee, StarknetError, StateDiff, StateUpdate, StorageEntry,
51    StorageProof, SubscriptionId, SyncStatus, TransactionExecutionErrorData,
52    TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceiptWithBlockInfo,
53    TransactionTraceWithHash, TransactionWithL2Status, TransactionWithReceipt,
54};
55
56/// Module containing the [`U256`] type.
57pub mod u256;
58pub use u256::U256;
59
60/// Module containing the [`EthAddress`] type.
61pub mod eth_address;
62pub use eth_address::EthAddress;
63
64/// Module containing the [`Hash256`] type.
65pub mod hash_256;
66pub use hash_256::Hash256;
67
68mod execution_result;
69pub use execution_result::ExecutionResult;
70
71mod message_status;
72pub use message_status::MessageStatus;
73
74mod receipt_block;
75pub use receipt_block::ReceiptBlock;
76
77mod msg;
78pub use msg::MsgToL2;
79
80mod call;
81pub use call::Call;
82
83mod byte_array;
84pub use byte_array::ByteArray;
85
86// TODO: move generated request code to `starknet-providers`
87/// Module containing JSON-RPC request types.
88pub mod requests;
89
90/// Module containing types related to Starknet contracts/classes.
91pub mod contract;
92pub use contract::ContractArtifact;
93
94/// A block with transaction hashes that may or may not be confirmed.
95///
96/// A pre-confirmed block lacks certain information on the block header compared to a confirmed
97/// block.
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99#[serde(untagged)]
100pub enum MaybePreConfirmedBlockWithTxHashes {
101    /// A confirmed block.
102    Block(BlockWithTxHashes),
103    /// A pre-confirmed block.
104    PreConfirmedBlock(PreConfirmedBlockWithTxHashes),
105}
106
107/// A block with full transactions that may or may not be confirmed.
108///
109/// A pre-confirmed block lacks certain information on the block header compared to a confirmed
110/// block.
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112#[serde(untagged)]
113pub enum MaybePreConfirmedBlockWithTxs {
114    /// A confirmed block.
115    Block(BlockWithTxs),
116    /// A pre-confirmed block.
117    PreConfirmedBlock(PreConfirmedBlockWithTxs),
118}
119
120/// A block with full transactions and receipts that may or may not be confirmed.
121///
122/// A pre-confirmed block lacks certain information on the block header compared to a confirmed
123/// block.
124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125#[serde(untagged)]
126pub enum MaybePreConfirmedBlockWithReceipts {
127    /// A confirmed block.
128    Block(BlockWithReceipts),
129    /// A pre-confirmed block.
130    PreConfirmedBlock(PreConfirmedBlockWithReceipts),
131}
132
133/// State update of a block that may or may not be confirmed.
134///
135/// State update for a pre-confirmed block lacks certain information compared to that of a confirmed
136/// block.
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(untagged)]
139pub enum MaybePreConfirmedStateUpdate {
140    /// The state update is for a confirmed block.
141    Update(StateUpdate),
142    /// The state update is for a pre-confirmed block.
143    PreConfirmedUpdate(PreConfirmedStateUpdate),
144}
145
146/// The hash and number (height) for a block.
147#[serde_as]
148#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
149pub struct BlockHashAndNumber {
150    /// The block's hash.
151    #[serde_as(as = "UfeHex")]
152    pub block_hash: Felt,
153    /// The block's number (height).
154    pub block_number: u64,
155}
156
157/// A Starknet client node's synchronization status.
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub enum SyncStatusType {
160    /// The node is synchronizing.
161    Syncing(SyncStatus),
162    /// The node is not synchronizing.
163    NotSyncing,
164}
165
166/// A "page" of events in a cursor-based pagniation system.
167///
168/// This type is usually returned from the `starknet_getEvents` RPC method.
169#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
170pub struct EventsPage {
171    /// Matching events
172    pub events: Vec<EmittedEvent>,
173    /// A pointer to the last element of the delivered page, use this token in a subsequent query to
174    /// obtain the next page. If the value is `None`, don't add it to the response as clients might
175    /// use `contains_key` as a check for the last page.
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub continuation_token: Option<String>,
178}
179
180/// Response for broadcasting an `INVOKE` transaction.
181#[serde_as]
182#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
183pub struct InvokeTransactionResult {
184    /// The hash of the invoke transaction
185    #[serde_as(as = "UfeHex")]
186    pub transaction_hash: Felt,
187}
188
189/// Response for broadcasting a `DECLARE` transaction.
190#[serde_as]
191#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
192pub struct DeclareTransactionResult {
193    /// The hash of the declare transaction
194    #[serde_as(as = "UfeHex")]
195    pub transaction_hash: Felt,
196    /// The hash of the declared class
197    #[serde_as(as = "UfeHex")]
198    pub class_hash: Felt,
199}
200
201/// Response for broadcasting a `DEPLOY` transaction.
202///
203/// Note that `DEPLOY` transactions have been deprecated and disabled on all public Starknet
204/// networks.
205#[serde_as]
206#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
207pub struct DeployTransactionResult {
208    /// The hash of the deploy transaction
209    #[serde_as(as = "UfeHex")]
210    pub transaction_hash: Felt,
211    /// The address of the new contract
212    #[serde_as(as = "UfeHex")]
213    pub contract_address: Felt,
214}
215
216/// Response for broadcasting a `DEPLOY_ACCOUNT` transaction.
217#[serde_as]
218#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
219pub struct DeployAccountTransactionResult {
220    /// The hash of the deploy transaction
221    #[serde_as(as = "UfeHex")]
222    pub transaction_hash: Felt,
223    /// The address of the new contract
224    #[serde_as(as = "UfeHex")]
225    pub contract_address: Felt,
226}
227
228/// Block identifier in the form of hash, number or tag.
229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
230pub enum BlockId {
231    /// Block hash.
232    Hash(Felt),
233    /// Block number (height).
234    Number(u64),
235    /// Block tag.
236    Tag(BlockTag),
237}
238
239/// Block identifier that refers to a confirmed block.
240#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241pub enum ConfirmedBlockId {
242    /// Block hash.
243    Hash(Felt),
244    /// Block number (height).
245    Number(u64),
246    /// The latest confirmed block.
247    Latest,
248    /// The latest Starknet block which was included in a state update on L1 and finalized by the
249    /// consensus on L1st,
250    L1Accepted,
251}
252
253/// A "processed" contract class representation that's circulated in the network. This is different
254/// from the class representation of compiler output.
255#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
256#[serde(untagged)]
257pub enum ContractClass {
258    /// A "processed" Sierra (Cairo 1) class.
259    Sierra(FlattenedSierraClass),
260    /// A "processed" legacy (Cairo 0) class.
261    Legacy(CompressedLegacyContractClass),
262}
263
264/// Represents the status of a transaction.
265#[derive(Debug, Clone, PartialEq, Eq)]
266pub enum TransactionStatus {
267    /// Transaction received by sequencer and awaiting processing.
268    Received,
269    /// Transaction is scheduled to be executed by sequencer.
270    Candidate,
271    /// Transaction pre-confirmed by sequencer but is not guaranteed to be included in a block.
272    PreConfirmed(ExecutionResult),
273    /// Transaction accepted on Layer 2 with a specific execution status.
274    AcceptedOnL2(ExecutionResult),
275    /// Transaction accepted on Layer 1 with a specific execution status.
276    AcceptedOnL1(ExecutionResult),
277}
278
279impl TransactionStatus {
280    /// Returns `true` if the transaction status is `Received`.
281    pub const fn is_received(&self) -> bool {
282        matches!(self, Self::Received)
283    }
284
285    /// Returns `true` if the transaction status is `Candidate`.
286    pub const fn is_candidate(&self) -> bool {
287        matches!(self, Self::Candidate)
288    }
289
290    /// Returns `true` if the transaction status is `PreConfirmed`.
291    pub const fn is_pre_confirmed(&self) -> bool {
292        matches!(self, Self::PreConfirmed(_))
293    }
294
295    /// Returns `true` if the transaction status is `AcceptedOnL2`.
296    pub const fn is_accepted_on_l2(&self) -> bool {
297        matches!(self, Self::AcceptedOnL2(_))
298    }
299
300    /// Returns `true` if the transaction status is `AcceptedOnL1`.
301    pub const fn is_accepted_on_l1(&self) -> bool {
302        matches!(self, Self::AcceptedOnL1(_))
303    }
304}
305
306/// A Starknet transaction or just its hash.
307#[allow(clippy::large_enum_variant)]
308#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
309#[serde(untagged)]
310pub enum TransactionOrHash {
311    /// The full transaction.
312    Transaction(Transaction),
313    /// The transaction hash only.
314    Hash(Felt),
315}
316
317/// A Starknet transaction.
318#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
319#[serde(tag = "type")]
320pub enum Transaction {
321    /// An `INVOKE` transaction.
322    #[serde(rename = "INVOKE")]
323    Invoke(InvokeTransaction),
324    /// An `L1_HANDLER` transaction.
325    #[serde(rename = "L1_HANDLER")]
326    L1Handler(L1HandlerTransaction),
327    /// A `DECLARE` transaction.
328    #[serde(rename = "DECLARE")]
329    Declare(DeclareTransaction),
330    /// A `DEPLOY` transaction.
331    #[serde(rename = "DEPLOY")]
332    Deploy(DeployTransaction),
333    /// A `DEPLOY_ACCOUNT` transaction.
334    #[serde(rename = "DEPLOY_ACCOUNT")]
335    DeployAccount(DeployAccountTransaction),
336}
337
338/// Content of a Starknet transaction without an annotated transaction hash.
339#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
340#[serde(tag = "type")]
341pub enum TransactionContent {
342    /// An `INVOKE` transaction.
343    #[serde(rename = "INVOKE")]
344    Invoke(InvokeTransactionContent),
345    /// An `L1_HANDLER` transaction.
346    #[serde(rename = "L1_HANDLER")]
347    L1Handler(L1HandlerTransactionContent),
348    /// A `DECLARE` transaction.
349    #[serde(rename = "DECLARE")]
350    Declare(DeclareTransactionContent),
351    /// A `DEPLOY` transaction.
352    #[serde(rename = "DEPLOY")]
353    Deploy(DeployTransactionContent),
354    /// A `DEPLOY_ACCOUNT` transaction.
355    #[serde(rename = "DEPLOY_ACCOUNT")]
356    DeployAccount(DeployAccountTransactionContent),
357}
358
359/// A Starknet transaction in its "mempool" representation that's broadcast by a client.
360#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
361#[serde(tag = "type")]
362pub enum BroadcastedTransaction {
363    /// An `INVOKE` transaction.
364    #[serde(rename = "INVOKE")]
365    Invoke(BroadcastedInvokeTransaction),
366    /// A `DECLARE` transaction.
367    #[serde(rename = "DECLARE")]
368    Declare(BroadcastedDeclareTransaction),
369    /// A `DEPLOY_ACCOUNT` transaction.
370    #[serde(rename = "DEPLOY_ACCOUNT")]
371    DeployAccount(BroadcastedDeployAccountTransaction),
372}
373
374/// An `INVOKE` Starknet transaction.
375#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
376#[serde(tag = "version")]
377pub enum InvokeTransaction {
378    /// Version 0 `INVOKE` transaction.
379    #[serde(rename = "0x0")]
380    V0(InvokeTransactionV0),
381    /// Version 1 `INVOKE` transaction.
382    #[serde(rename = "0x1")]
383    V1(InvokeTransactionV1),
384    /// Version 3 `INVOKE` transaction.
385    #[serde(rename = "0x3")]
386    V3(InvokeTransactionV3),
387}
388
389/// Content of an `INVOKE` Starknet transaction.
390#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
391#[serde(tag = "version")]
392pub enum InvokeTransactionContent {
393    /// Version 0 `INVOKE` transaction.
394    #[serde(rename = "0x0")]
395    V0(InvokeTransactionV0Content),
396    /// Version 1 `INVOKE` transaction.
397    #[serde(rename = "0x1")]
398    V1(InvokeTransactionV1Content),
399    /// Version 3 `INVOKE` transaction.
400    #[serde(rename = "0x3")]
401    V3(InvokeTransactionV3Content),
402}
403
404/// A `DECLARE` Starknet transaction.
405#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
406#[serde(tag = "version")]
407pub enum DeclareTransaction {
408    /// Version 0 `DECLARE` transaction.
409    #[serde(rename = "0x0")]
410    V0(DeclareTransactionV0),
411    /// Version 1 `DECLARE` transaction.
412    #[serde(rename = "0x1")]
413    V1(DeclareTransactionV1),
414    /// Version 2 `DECLARE` transaction.
415    #[serde(rename = "0x2")]
416    V2(DeclareTransactionV2),
417    /// Version 3 `DECLARE` transaction.
418    #[serde(rename = "0x3")]
419    V3(DeclareTransactionV3),
420}
421
422/// Content of a `DECLARE` Starknet transaction.
423#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
424#[serde(tag = "version")]
425pub enum DeclareTransactionContent {
426    /// Version 0 `DECLARE` transaction.
427    #[serde(rename = "0x0")]
428    V0(DeclareTransactionV0Content),
429    /// Version 1 `DECLARE` transaction.
430    #[serde(rename = "0x1")]
431    V1(DeclareTransactionV1Content),
432    /// Version 2 `DECLARE` transaction.
433    #[serde(rename = "0x2")]
434    V2(DeclareTransactionV2Content),
435    /// Version 3 `DECLARE` transaction.
436    #[serde(rename = "0x3")]
437    V3(DeclareTransactionV3Content),
438}
439
440/// A `DEPLOY_ACCOUNT` Starknet transaction.
441#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
442#[serde(tag = "version")]
443pub enum DeployAccountTransaction {
444    /// Version 1 `DEPLOY_ACCOUNT` transaction.
445    #[serde(rename = "0x1")]
446    V1(DeployAccountTransactionV1),
447    /// Version 3 `DEPLOY_ACCOUNT` transaction.
448    #[serde(rename = "0x3")]
449    V3(DeployAccountTransactionV3),
450}
451
452/// Content of a `DEPLOY_ACCOUNT` Starknet transaction.
453#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
454#[serde(tag = "version")]
455pub enum DeployAccountTransactionContent {
456    /// Version 1 `DEPLOY_ACCOUNT` transaction.
457    #[serde(rename = "0x1")]
458    V1(DeployAccountTransactionV1Content),
459    /// Version 3 `DEPLOY_ACCOUNT` transaction.
460    #[serde(rename = "0x3")]
461    V3(DeployAccountTransactionV3Content),
462}
463
464/// Starknet transaction receipt containing execution results.
465#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
466#[serde(tag = "type")]
467pub enum TransactionReceipt {
468    /// Receipt for an `INVOKE` transaction.
469    #[serde(rename = "INVOKE")]
470    Invoke(InvokeTransactionReceipt),
471    /// Receipt for an `L1_HANDLER` transaction.
472    #[serde(rename = "L1_HANDLER")]
473    L1Handler(L1HandlerTransactionReceipt),
474    /// Receipt for a `DECLARE` transaction.
475    #[serde(rename = "DECLARE")]
476    Declare(DeclareTransactionReceipt),
477    /// Receipt for a `DEPLOY` transaction.
478    #[serde(rename = "DEPLOY")]
479    Deploy(DeployTransactionReceipt),
480    /// Receipt for a `DEPLOY_ACCOUNT` transaction.
481    #[serde(rename = "DEPLOY_ACCOUNT")]
482    DeployAccount(DeployAccountTransactionReceipt),
483}
484
485/// ABI entry item for legacy (Cairo 0) contract classes.
486#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
487#[serde(untagged)]
488pub enum LegacyContractAbiEntry {
489    /// ABI entry representing a Cairo function.
490    Function(LegacyFunctionAbiEntry),
491    /// ABI entry representing a Starknet event.
492    Event(LegacyEventAbiEntry),
493    /// ABI entry representing a Cairo struct.
494    Struct(LegacyStructAbiEntry),
495}
496
497/// Execution trace of a Starknet transaction.
498#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
499#[serde(tag = "type")]
500pub enum TransactionTrace {
501    /// Trace for an `INVOKE` transaction.
502    #[serde(rename = "INVOKE")]
503    Invoke(InvokeTransactionTrace),
504    /// Trace for a `DEPLOY_ACCOUNT` transaction.
505    #[serde(rename = "DEPLOY_ACCOUNT")]
506    DeployAccount(DeployAccountTransactionTrace),
507    /// Trace for an `L1_HANDLER` transaction.
508    #[serde(rename = "L1_HANDLER")]
509    L1Handler(L1HandlerTransactionTrace),
510    /// Trace for a `DECLARE` transaction.
511    #[serde(rename = "DECLARE")]
512    Declare(DeclareTransactionTrace),
513}
514
515/// The execution result of a function invocation.
516#[allow(clippy::large_enum_variant)]
517#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
518#[serde(untagged)]
519pub enum ExecuteInvocation {
520    /// Successful invocation.
521    Success(FunctionInvocation),
522    /// Failed and reverted invocation.
523    Reverted(RevertedInvocation),
524}
525
526/// A node in the Merkle-Patricia tree, can be a leaf, binary node, or an edge node.
527#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
528#[serde(untagged)]
529pub enum MerkleNode {
530    /// Binary/branch node.
531    BinaryNode(BinaryNode),
532    /// Edge/leaf node.
533    EdgeNode(EdgeNode),
534}
535
536/// Structured error that can later be processed by wallets or sdks.
537#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
538#[serde(untagged)]
539pub enum ContractExecutionError {
540    /// Nested contract call stack trace frame.
541    Nested(InnerContractExecutionError),
542    /// Terminal error message.
543    Message(String),
544}
545
546mod errors {
547    use core::fmt::{Display, Formatter, Result};
548
549    /// Errors parsing an L1-to-L2 message from transaction calldata.
550    #[derive(Debug, PartialEq, Eq)]
551    pub enum ParseMsgToL2Error {
552        /// The transaction calldata is empty.
553        EmptyCalldata,
554        /// The L1 sender address is longer than 20 bytes.
555        FromAddressOutOfRange,
556    }
557
558    #[cfg(feature = "std")]
559    impl std::error::Error for ParseMsgToL2Error {}
560
561    impl Display for ParseMsgToL2Error {
562        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
563            match self {
564                Self::EmptyCalldata => {
565                    write!(
566                        f,
567                        "calldata must contain at least 1 element for from_address"
568                    )
569                }
570                Self::FromAddressOutOfRange => {
571                    write!(f, "from_address is larger than 20 bytes")
572                }
573            }
574        }
575    }
576}
577pub use errors::ParseMsgToL2Error;
578
579impl MaybePreConfirmedBlockWithTxHashes {
580    /// Gets a reference to the list of transaction hashes.
581    pub fn transactions(&self) -> &[Felt] {
582        match self {
583            Self::Block(block) => &block.transactions,
584            Self::PreConfirmedBlock(block) => &block.transactions,
585        }
586    }
587
588    /// Gets a reference to the L1 gas price.
589    pub const fn l1_gas_price(&self) -> &ResourcePrice {
590        match self {
591            Self::Block(block) => &block.l1_gas_price,
592            Self::PreConfirmedBlock(block) => &block.l1_gas_price,
593        }
594    }
595
596    /// Gets a reference to the L2 gas price.
597    pub const fn l2_gas_price(&self) -> &ResourcePrice {
598        match self {
599            Self::Block(block) => &block.l2_gas_price,
600            Self::PreConfirmedBlock(block) => &block.l2_gas_price,
601        }
602    }
603
604    /// Gets a reference to the L1 data gas price.
605    pub const fn l1_data_gas_price(&self) -> &ResourcePrice {
606        match self {
607            Self::Block(block) => &block.l1_data_gas_price,
608            Self::PreConfirmedBlock(block) => &block.l1_data_gas_price,
609        }
610    }
611}
612
613impl MaybePreConfirmedBlockWithTxs {
614    /// Gets a reference to the list of transactions.
615    pub fn transactions(&self) -> &[Transaction] {
616        match self {
617            Self::Block(block) => &block.transactions,
618            Self::PreConfirmedBlock(block) => &block.transactions,
619        }
620    }
621
622    /// Gets a reference to the L1 gas price.
623    pub const fn l1_gas_price(&self) -> &ResourcePrice {
624        match self {
625            Self::Block(block) => &block.l1_gas_price,
626            Self::PreConfirmedBlock(block) => &block.l1_gas_price,
627        }
628    }
629
630    /// Gets a reference to the L2 gas price.
631    pub const fn l2_gas_price(&self) -> &ResourcePrice {
632        match self {
633            Self::Block(block) => &block.l2_gas_price,
634            Self::PreConfirmedBlock(block) => &block.l2_gas_price,
635        }
636    }
637
638    /// Gets a reference to the L1 data gas price.
639    pub const fn l1_data_gas_price(&self) -> &ResourcePrice {
640        match self {
641            Self::Block(block) => &block.l1_data_gas_price,
642            Self::PreConfirmedBlock(block) => &block.l1_data_gas_price,
643        }
644    }
645
646    /// Calculates the median tip amount paid by transactions that support tips.
647    ///
648    /// Note that the calculation *excludes* transaction types and versions that simply do not
649    /// support tips.
650    ///
651    /// Returns `0` if the block contains no eligible transactions.
652    pub fn median_tip(&self) -> u64 {
653        let mut tips: Vec<u64> = self
654            .transactions()
655            .iter()
656            .filter_map(|tx| tx.tip())
657            .collect();
658
659        if tips.is_empty() {
660            // If no transactions have tips, use 0
661            0
662        } else {
663            tips.sort_unstable();
664            let len = tips.len();
665            if len.is_multiple_of(2) {
666                // Even number of tips: average of two middle values
667                (tips[len / 2 - 1] + tips[len / 2]) / 2
668            } else {
669                // Odd number of tips: middle value
670                tips[len / 2]
671            }
672        }
673    }
674}
675
676impl MaybePreConfirmedBlockWithReceipts {
677    /// Gets a reference to the list of transactions with receipts.
678    pub fn transactions(&self) -> &[TransactionWithReceipt] {
679        match self {
680            Self::Block(block) => &block.transactions,
681            Self::PreConfirmedBlock(block) => &block.transactions,
682        }
683    }
684
685    /// Gets a reference to the L1 gas price.
686    pub const fn l1_gas_price(&self) -> &ResourcePrice {
687        match self {
688            Self::Block(block) => &block.l1_gas_price,
689            Self::PreConfirmedBlock(block) => &block.l1_gas_price,
690        }
691    }
692}
693
694impl TransactionStatus {
695    /// Gets a reference to the transaction's finality status.
696    pub const fn finality_status(&self) -> SequencerTransactionStatus {
697        match self {
698            Self::Received => SequencerTransactionStatus::Received,
699            Self::Candidate => SequencerTransactionStatus::Candidate,
700            Self::PreConfirmed(_) => SequencerTransactionStatus::PreConfirmed,
701            Self::AcceptedOnL2(_) => SequencerTransactionStatus::AcceptedOnL2,
702            Self::AcceptedOnL1(_) => SequencerTransactionStatus::AcceptedOnL1,
703        }
704    }
705}
706
707impl Transaction {
708    /// Gets a reference to the transaction's hash.
709    pub const fn transaction_hash(&self) -> &Felt {
710        match self {
711            Self::Invoke(tx) => tx.transaction_hash(),
712            Self::L1Handler(tx) => &tx.transaction_hash,
713            Self::Declare(tx) => tx.transaction_hash(),
714            Self::Deploy(tx) => &tx.transaction_hash,
715            Self::DeployAccount(tx) => tx.transaction_hash(),
716        }
717    }
718
719    /// Gets the transaction's tip amount.
720    ///
721    /// Returns `None` if the transaction's type or version does not support tips.
722    pub const fn tip(&self) -> Option<u64> {
723        match self {
724            Self::Invoke(InvokeTransaction::V3(tx)) => Some(tx.tip),
725            Self::Declare(DeclareTransaction::V3(tx)) => Some(tx.tip),
726            Self::DeployAccount(DeployAccountTransaction::V3(tx)) => Some(tx.tip),
727            // Exhaust all variants to force a compilation error upon adding new variants
728            Self::Invoke(InvokeTransaction::V0(_))
729            | Self::Invoke(InvokeTransaction::V1(_))
730            | Self::L1Handler(_)
731            | Self::Declare(DeclareTransaction::V0(_))
732            | Self::Declare(DeclareTransaction::V1(_))
733            | Self::Declare(DeclareTransaction::V2(_))
734            | Self::Deploy(_)
735            | Self::DeployAccount(DeployAccountTransaction::V1(_)) => None,
736        }
737    }
738}
739
740impl InvokeTransaction {
741    /// Gets a reference to the transaction's hash.
742    pub const fn transaction_hash(&self) -> &Felt {
743        match self {
744            Self::V0(tx) => &tx.transaction_hash,
745            Self::V1(tx) => &tx.transaction_hash,
746            Self::V3(tx) => &tx.transaction_hash,
747        }
748    }
749}
750
751impl DeclareTransaction {
752    /// Gets a reference to the transaction's hash.
753    pub const fn transaction_hash(&self) -> &Felt {
754        match self {
755            Self::V0(tx) => &tx.transaction_hash,
756            Self::V1(tx) => &tx.transaction_hash,
757            Self::V2(tx) => &tx.transaction_hash,
758            Self::V3(tx) => &tx.transaction_hash,
759        }
760    }
761}
762
763impl DeployAccountTransaction {
764    /// Gets a reference to the transaction's hash.
765    pub const fn transaction_hash(&self) -> &Felt {
766        match self {
767            Self::V1(tx) => &tx.transaction_hash,
768            Self::V3(tx) => &tx.transaction_hash,
769        }
770    }
771}
772
773impl TransactionReceipt {
774    /// Gets a reference to the transaction's hash.
775    pub const fn transaction_hash(&self) -> &Felt {
776        match self {
777            Self::Invoke(receipt) => &receipt.transaction_hash,
778            Self::L1Handler(receipt) => &receipt.transaction_hash,
779            Self::Declare(receipt) => &receipt.transaction_hash,
780            Self::Deploy(receipt) => &receipt.transaction_hash,
781            Self::DeployAccount(receipt) => &receipt.transaction_hash,
782        }
783    }
784
785    /// Gets a reference to the transaction's finality status.
786    pub const fn finality_status(&self) -> &TransactionFinalityStatus {
787        match self {
788            Self::Invoke(receipt) => &receipt.finality_status,
789            Self::L1Handler(receipt) => &receipt.finality_status,
790            Self::Declare(receipt) => &receipt.finality_status,
791            Self::Deploy(receipt) => &receipt.finality_status,
792            Self::DeployAccount(receipt) => &receipt.finality_status,
793        }
794    }
795
796    /// Gets a reference to the transaction's execution result.
797    pub const fn execution_result(&self) -> &ExecutionResult {
798        match self {
799            Self::Invoke(receipt) => &receipt.execution_result,
800            Self::L1Handler(receipt) => &receipt.execution_result,
801            Self::Declare(receipt) => &receipt.execution_result,
802            Self::Deploy(receipt) => &receipt.execution_result,
803            Self::DeployAccount(receipt) => &receipt.execution_result,
804        }
805    }
806
807    /// Gets a reference to the transaction's emitted events.
808    pub fn events(&self) -> &[Event] {
809        match self {
810            Self::Invoke(receipt) => &receipt.events,
811            Self::L1Handler(receipt) => &receipt.events,
812            Self::Declare(receipt) => &receipt.events,
813            Self::Deploy(receipt) => &receipt.events,
814            Self::DeployAccount(receipt) => &receipt.events,
815        }
816    }
817}
818
819impl L1HandlerTransaction {
820    /// Parses [`MsgToL2`] from the transaction's calldata. This should not never fail on a genuine
821    /// `L1_HANDLER` transaction.
822    pub fn parse_msg_to_l2(&self) -> Result<MsgToL2, ParseMsgToL2Error> {
823        self.calldata.split_first().map_or(
824            Err(ParseMsgToL2Error::EmptyCalldata),
825            |(from_address, payload)| {
826                Ok(MsgToL2 {
827                    from_address: (*from_address)
828                        .try_into()
829                        .map_err(|_| ParseMsgToL2Error::FromAddressOutOfRange)?,
830                    to_address: self.contract_address,
831                    selector: self.entry_point_selector,
832                    payload: payload.into(),
833                    nonce: self.nonce,
834                })
835            },
836        )
837    }
838}
839
840impl AsRef<Self> for BlockId {
841    fn as_ref(&self) -> &Self {
842        self
843    }
844}
845
846impl AsRef<Self> for ConfirmedBlockId {
847    fn as_ref(&self) -> &Self {
848        self
849    }
850}
851
852impl AsRef<Self> for FunctionCall {
853    fn as_ref(&self) -> &Self {
854        self
855    }
856}
857
858impl AsRef<Self> for MsgFromL1 {
859    fn as_ref(&self) -> &Self {
860        self
861    }
862}
863
864impl AsRef<Self> for BroadcastedTransaction {
865    fn as_ref(&self) -> &Self {
866        self
867    }
868}
869
870impl AsRef<Self> for BroadcastedInvokeTransaction {
871    fn as_ref(&self) -> &Self {
872        self
873    }
874}
875
876impl AsRef<Self> for BroadcastedDeclareTransaction {
877    fn as_ref(&self) -> &Self {
878        self
879    }
880}
881
882impl AsRef<Self> for BroadcastedDeployAccountTransaction {
883    fn as_ref(&self) -> &Self {
884        self
885    }
886}
887
888impl TryFrom<&L1HandlerTransaction> for MsgToL2 {
889    type Error = ParseMsgToL2Error;
890
891    fn try_from(value: &L1HandlerTransaction) -> Result<Self, Self::Error> {
892        value.parse_msg_to_l2()
893    }
894}
895
896#[cfg(test)]
897mod tests {
898    use super::{requests::*, *};
899
900    #[test]
901    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
902    fn test_felt_to_string() {
903        let felt = Felt::from_dec_str("123456").unwrap();
904
905        assert_eq!(format!("{felt}"), "123456");
906        assert_eq!(format!("{felt:x}"), "1e240");
907        assert_eq!(format!("{felt:X}"), "1E240");
908        assert_eq!(format!("{felt:#x}"), "0x1e240");
909        assert_eq!(format!("{felt:#X}"), "0x1E240");
910        assert_eq!(format!("{felt:010x}"), "000001e240");
911        assert_eq!(format!("{felt:010X}"), "000001E240");
912        assert_eq!(format!("{felt:#010x}"), "0x000001e240");
913        assert_eq!(format!("{felt:#010X}"), "0x000001E240");
914    }
915
916    #[test]
917    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
918    fn test_parse_msg_to_l2() {
919        let l1_handler_tx = L1HandlerTransaction {
920            transaction_hash: Felt::from_hex(
921                "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c",
922            )
923            .unwrap(),
924            version: Felt::ZERO,
925            nonce: 775628,
926            contract_address: Felt::from_hex(
927                "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
928            )
929            .unwrap(),
930            entry_point_selector: Felt::from_hex(
931                "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
932            )
933            .unwrap(),
934            calldata: vec![
935                Felt::from_hex("0xc3511006c04ef1d78af4c8e0e74ec18a6e64ff9e").unwrap(),
936                Felt::from_hex("0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7")
937                    .unwrap(),
938                Felt::from_hex("0x2c68af0bb140000").unwrap(),
939                Felt::from_hex("0x0").unwrap(),
940            ],
941        };
942
943        let msg_to_l2 = l1_handler_tx.parse_msg_to_l2().unwrap();
944
945        let expected_hash =
946            Hash256::from_hex("c51a543ef9563ad2545342b390b67edfcddf9886aa36846cf70382362fc5fab3")
947                .unwrap();
948
949        assert_eq!(msg_to_l2.hash(), expected_hash);
950    }
951
952    #[test]
953    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
954    fn test_parse_msg_to_l2_empty_calldata_error() {
955        let l1_handler_tx = L1HandlerTransaction {
956            transaction_hash: Felt::from_hex(
957                "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c",
958            )
959            .unwrap(),
960            version: Felt::ZERO,
961            nonce: 775628,
962            contract_address: Felt::from_hex(
963                "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
964            )
965            .unwrap(),
966            entry_point_selector: Felt::from_hex(
967                "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
968            )
969            .unwrap(),
970            calldata: Vec::new(), // Empty calldata
971        };
972
973        let result = l1_handler_tx.parse_msg_to_l2();
974
975        assert_eq!(result.unwrap_err(), ParseMsgToL2Error::EmptyCalldata);
976    }
977
978    #[test]
979    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
980    fn test_parse_msg_to_l2_from_address_out_of_range_error() {
981        let l1_handler_tx = L1HandlerTransaction {
982            transaction_hash: Felt::from_hex(
983                "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c",
984            )
985            .unwrap(),
986            version: Felt::ZERO,
987            nonce: 775628,
988            contract_address: Felt::from_hex(
989                "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82",
990            )
991            .unwrap(),
992            entry_point_selector: Felt::from_hex(
993                "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5",
994            )
995            .unwrap(),
996            calldata: vec![
997                // Incorrect from address format, causing the conversion error
998                // Max address + 1
999                Felt::from_hex("0x10000000000000000000000000000000000000000").unwrap(),
1000                Felt::from_hex("0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7")
1001                    .unwrap(),
1002                Felt::from_hex("0x2c68af0bb140000").unwrap(),
1003                Felt::from_hex("0x0").unwrap(),
1004            ],
1005        };
1006
1007        let result = l1_handler_tx.parse_msg_to_l2();
1008
1009        assert_eq!(
1010            result.unwrap_err(),
1011            ParseMsgToL2Error::FromAddressOutOfRange
1012        );
1013    }
1014
1015    #[test]
1016    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1017    fn test_parse_get_block_transaction_count_request() {
1018        let as_object = r#"{"block_id":{"block_number":200}}"#;
1019        let as_array = r#"[{"block_number":200}]"#;
1020
1021        assert_eq!(
1022            GetBlockTransactionCountRequest {
1023                block_id: BlockId::Number(200)
1024            },
1025            serde_json::from_str(as_object).unwrap(),
1026        );
1027
1028        assert_eq!(
1029            GetBlockTransactionCountRequest {
1030                block_id: BlockId::Number(200)
1031            },
1032            serde_json::from_str(as_array).unwrap(),
1033        );
1034    }
1035
1036    #[test]
1037    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1038    fn test_parse_get_storage_proof_request() {
1039        let as_object = r#"{"block_id":{"block_number":200},"class_hashes":["0x123"]}"#;
1040        let as_array = r#"[{"block_number":200},["0x123"]]"#;
1041
1042        assert_eq!(
1043            GetStorageProofRequest {
1044                block_id: ConfirmedBlockId::Number(200),
1045                class_hashes: Some(vec![Felt::from_hex_unchecked("0x123")]),
1046                contract_addresses: None,
1047                contracts_storage_keys: None
1048            },
1049            serde_json::from_str(as_object).unwrap(),
1050        );
1051
1052        assert_eq!(
1053            GetStorageProofRequest {
1054                block_id: ConfirmedBlockId::Number(200),
1055                class_hashes: Some(vec![Felt::from_hex_unchecked("0x123")]),
1056                contract_addresses: None,
1057                contracts_storage_keys: None
1058            },
1059            serde_json::from_str(as_array).unwrap(),
1060        );
1061    }
1062}