openzeppelin_monitor/models/blockchain/midnight/
event.rs

1//! Midnight event data structures.
2//!
3//! This module defines the event types and structures used in the Midnight blockchain.
4//! Events are emitted during transaction execution and represent various state changes
5//! in the blockchain, such as contract deployments, calls, and transaction applications.
6//!
7//! The structures are based on the Midnight Node implementation:
8//! <https://github.com/midnightntwrk/midnight-node/blob/39dbdf54afc5f0be7e7913b387637ac52d0c50f2/pallets/midnight/src/lib.rs#L149-L205>
9//! <https://github.com/midnightntwrk/midnight-node/blob/39dbdf54afc5f0be7e7913b387637ac52d0c50f2/runtime/src/model.rs#L26-L187>
10
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13use std::ops::{Deref, DerefMut};
14
15/// Represents the phase of a blockchain event.
16///
17/// Events can occur during different phases of block processing:
18/// - During extrinsic application (with the extrinsic index)
19/// - During block finalization
20/// - During block initialization
21#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
22pub enum Phase {
23	/// Event occurred during extrinsic application.
24	/// The associated value is the index of the extrinsic in the block.
25	ApplyExtrinsic(u32),
26	/// Event occurred during block finalization.
27	Finalization,
28	/// Event occurred during block initialization.
29	Initialization,
30}
31
32impl Default for Phase {
33	fn default() -> Self {
34		Self::ApplyExtrinsic(0)
35	}
36}
37
38/// Contains a list of topics associated with an event.
39///
40/// Topics are used for event filtering and indexing in the blockchain.
41/// Each topic is a string that can be used to categorize or filter events.
42#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Default)]
43pub struct Topics {
44	/// List of topic strings associated with the event.
45	pub topics: Vec<String>,
46}
47
48/// Details of a transaction that has been applied to the blockchain.
49///
50/// This structure contains information about a transaction that has been
51/// successfully processed and included in a block.
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
53pub struct TxAppliedDetails {
54	/// The phase during which the transaction was applied.
55	pub phase: Phase,
56	/// Topics associated with the transaction application.
57	pub topics: Topics,
58	/// The hash of the applied transaction.
59	pub tx_hash: String,
60}
61
62/// Details of a contract maintenance operation.
63///
64/// This structure contains information about a contract ownership change
65/// that enables SNARK upgrades or other maintenance operations.
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
67pub struct MaintainDetails {
68	/// The phase during which the maintenance operation occurred.
69	pub phase: Phase,
70	/// Topics associated with the maintenance operation.
71	pub topics: Topics,
72	/// The address of the contract being maintained.
73	pub address: String,
74	/// The hash of the transaction that performed the maintenance.
75	pub tx_hash: String,
76}
77
78/// Details of a contract deployment.
79///
80/// This structure contains information about a newly deployed contract,
81/// including its address and the transaction that created it.
82#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
83pub struct DeploymentDetails {
84	/// The phase during which the contract was deployed.
85	pub phase: Phase,
86	/// Topics associated with the contract deployment.
87	pub topics: Topics,
88	/// The address of the newly deployed contract.
89	pub address: String,
90	/// The hash of the transaction that deployed the contract.
91	pub tx_hash: String,
92}
93
94/// Details of a contract call.
95///
96/// This structure contains information about a function call to a contract,
97/// including the contract address and the transaction that made the call.
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
99pub struct CallDetails {
100	/// The phase during which the contract call occurred.
101	pub phase: Phase,
102	/// Topics associated with the contract call.
103	pub topics: Topics,
104	/// The address of the contract being called.
105	pub address: String,
106	/// The hash of the transaction that made the call.
107	pub tx_hash: String,
108}
109
110/// Details of a mint claim operation.
111///
112/// This structure contains information about a claim for minted tokens,
113/// including the coin type, amount, and the transaction that made the claim.
114#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
115pub struct ClaimMintDetails {
116	/// The phase during which the mint claim occurred.
117	pub phase: Phase,
118	/// Topics associated with the mint claim.
119	pub topics: Topics,
120	/// The type of coin being claimed.
121	pub coin_type: String,
122	/// The amount of tokens being claimed.
123	pub value: u128,
124	/// The hash of the transaction that made the claim.
125	pub tx_hash: String,
126}
127
128/// Details of a payout operation.
129///
130/// This structure contains information about a payout of tokens,
131/// including the amount and the recipient's address.
132#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
133pub struct PayoutDetails {
134	/// The phase during which the payout occurred.
135	pub phase: Phase,
136	/// Topics associated with the payout.
137	pub topics: Topics,
138	/// The amount of tokens being paid out.
139	pub amount: u128,
140	/// The address of the recipient.
141	pub receiver: String,
142}
143
144/// Enum representing different types of events that can occur in the Midnight blockchain.
145///
146/// Each variant contains specific details about the event type, such as contract calls,
147/// deployments, or transaction applications. This enum is used to categorize and process
148/// different types of blockchain events.
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub enum EventType {
151	/// A contract was called.
152	/// Contains details about the contract call, including the contract address and transaction hash.
153	MidnightCallContract(CallDetails),
154	/// A contract has been deployed.
155	/// Contains details about the contract deployment, including the new contract address and transaction hash.
156	MidnightDeployContract(DeploymentDetails),
157	/// A transaction has been applied (both the guaranteed and conditional part).
158	/// Contains details about the fully applied transaction.
159	MidnightTxApplied(TxAppliedDetails),
160	/// Only guaranteed transactions have been applied.
161	/// Contains details about the partially applied transaction (guaranteed part only).
162	MidnightOnlyGuaranteedTxApplied(TxAppliedDetails),
163	/// Contract ownership changes to enable snark upgrades.
164	/// Contains details about the contract maintenance operation.
165	MidnightMaintainContract(MaintainDetails),
166	/// New payout minted.
167	/// Contains details about a new token payout, including amount and recipient.
168	MidnightPayoutMinted(PayoutDetails),
169	/// Payout was claimed.
170	/// Contains details about a claim for minted tokens.
171	MidnightClaimMint(ClaimMintDetails),
172	/// Unknown event type.
173	/// A default variant for when the event type is not known or not Midnight specific.
174	/// Contains details about an unknown event type.
175	Unknown(String),
176}
177
178impl Default for EventType {
179	fn default() -> Self {
180		Self::Unknown(format!(
181			"Unknown event type: {}",
182			std::any::type_name::<Self>()
183		))
184	}
185}
186
187/// Wrapper around EventType that provides additional functionality.
188///
189/// This type implements convenience methods for working with Midnight events
190/// while maintaining compatibility with the RPC response format. It serves as the
191/// primary interface for handling events in the Midnight blockchain.
192#[derive(Deserialize, Serialize, Debug, Clone)]
193pub struct Event(pub EventType);
194
195/// Additional methods for Event
196impl Event {
197	/// Check if the event is a transaction applied event.
198	pub fn is_tx_applied(&self) -> bool {
199		matches!(self.0, EventType::MidnightTxApplied(_))
200	}
201
202	/// Check if the event is a transaction applied event.
203	pub fn is_only_guaranteed_tx_applied(&self) -> bool {
204		matches!(self.0, EventType::MidnightOnlyGuaranteedTxApplied(_))
205	}
206
207	/// Check if the event is a success event.
208	///
209	/// This is a convenience method that checks if the event is a transaction applied event
210	/// or an only guaranteed transaction applied event.
211	pub fn is_success(&self) -> bool {
212		self.is_tx_applied() || self.is_only_guaranteed_tx_applied()
213	}
214
215	/// Get the transaction hash from the event.
216	///
217	/// This method returns the transaction hash from the event.
218	pub fn get_tx_hash(&self) -> Option<String> {
219		match &self.0 {
220			EventType::MidnightTxApplied(details) => Some(details.tx_hash.clone()),
221			EventType::MidnightOnlyGuaranteedTxApplied(details) => Some(details.tx_hash.clone()),
222			EventType::MidnightCallContract(details) => Some(details.tx_hash.clone()),
223			EventType::MidnightDeployContract(details) => Some(details.tx_hash.clone()),
224			EventType::MidnightMaintainContract(details) => Some(details.tx_hash.clone()),
225			EventType::MidnightClaimMint(details) => Some(details.tx_hash.clone()),
226			EventType::MidnightPayoutMinted(_) => None,
227			EventType::Unknown(_) => None,
228		}
229	}
230
231	/// Get the topics from the event.
232	///
233	/// This method returns the topics from the event.
234	pub fn get_topics(&self) -> Option<Vec<String>> {
235		match &self.0 {
236			EventType::MidnightTxApplied(details) => Some(details.topics.topics.clone()),
237			EventType::MidnightOnlyGuaranteedTxApplied(details) => {
238				Some(details.topics.topics.clone())
239			}
240			EventType::MidnightCallContract(details) => Some(details.topics.topics.clone()),
241			EventType::MidnightDeployContract(details) => Some(details.topics.topics.clone()),
242			EventType::MidnightMaintainContract(details) => Some(details.topics.topics.clone()),
243			EventType::MidnightPayoutMinted(details) => Some(details.topics.topics.clone()),
244			EventType::MidnightClaimMint(details) => Some(details.topics.topics.clone()),
245			EventType::Unknown(_) => None,
246		}
247	}
248
249	/// Get the phase from the event.
250	///
251	/// This method returns the phase from the event.
252	pub fn get_phase(&self) -> Option<Phase> {
253		match &self.0 {
254			EventType::MidnightTxApplied(details) => Some(details.phase.clone()),
255			EventType::MidnightOnlyGuaranteedTxApplied(details) => Some(details.phase.clone()),
256			EventType::MidnightCallContract(details) => Some(details.phase.clone()),
257			EventType::MidnightDeployContract(details) => Some(details.phase.clone()),
258			EventType::MidnightMaintainContract(details) => Some(details.phase.clone()),
259			EventType::MidnightPayoutMinted(details) => Some(details.phase.clone()),
260			EventType::MidnightClaimMint(details) => Some(details.phase.clone()),
261			EventType::Unknown(_) => None,
262		}
263	}
264}
265
266/// Dereference the EventType
267impl Deref for Event {
268	type Target = EventType;
269
270	fn deref(&self) -> &Self::Target {
271		&self.0
272	}
273}
274
275impl DerefMut for Event {
276	fn deref_mut(&mut self) -> &mut Self::Target {
277		&mut self.0
278	}
279}
280
281impl From<EventType> for Event {
282	fn from(event_type: EventType) -> Self {
283		Self(event_type)
284	}
285}
286
287impl From<Event> for EventType {
288	fn from(event: Event) -> Self {
289		event.0
290	}
291}
292
293impl From<Value> for Event {
294	fn from(value: Value) -> Self {
295		match serde_json::from_value::<EventType>(value) {
296			Ok(event_type) => Event(event_type),
297			Err(e) => Event(EventType::Unknown(format!(
298				"Failed to deserialize event: {}",
299				e.to_string().split(",").next().unwrap_or_default()
300			))),
301		}
302	}
303}
304
305#[cfg(test)]
306mod tests {
307	use super::*;
308	use serde_json::json;
309
310	#[test]
311	fn test_tx_applied_details() {
312		let details = TxAppliedDetails {
313			phase: Phase::default(),
314			topics: Topics::default(),
315			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
316				.to_string(),
317		};
318		assert_eq!(
319			details.tx_hash,
320			"0x0000000000000000000000000000000000000000000000000000000000000000"
321		);
322	}
323
324	#[test]
325	fn test_maintain_details() {
326		let details = MaintainDetails {
327			phase: Phase::default(),
328			topics: Topics::default(),
329			address: "0x123".to_string(),
330			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
331				.to_string(),
332		};
333		assert_eq!(
334			details.tx_hash,
335			"0x0000000000000000000000000000000000000000000000000000000000000000"
336		);
337		assert_eq!(details.address, "0x123");
338	}
339
340	#[test]
341	fn test_deployment_details() {
342		let details = DeploymentDetails {
343			phase: Phase::default(),
344			topics: Topics::default(),
345			address: "0x123".to_string(),
346			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
347				.to_string(),
348		};
349		assert_eq!(
350			details.tx_hash,
351			"0x0000000000000000000000000000000000000000000000000000000000000000"
352		);
353		assert_eq!(details.address, "0x123");
354	}
355
356	#[test]
357	fn test_call_details() {
358		let details = CallDetails {
359			phase: Phase::default(),
360			topics: Topics::default(),
361			address: "0x123".to_string(),
362			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
363				.to_string(),
364		};
365		assert_eq!(
366			details.tx_hash,
367			"0x0000000000000000000000000000000000000000000000000000000000000000"
368		);
369		assert_eq!(details.address, "0x123");
370	}
371
372	#[test]
373	fn test_claim_mint_details() {
374		let details = ClaimMintDetails {
375			phase: Phase::default(),
376			topics: Topics::default(),
377			coin_type: "0x123".to_string(),
378			value: 100u128,
379			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
380				.to_string(),
381		};
382		assert_eq!(
383			details.tx_hash,
384			"0x0000000000000000000000000000000000000000000000000000000000000000"
385		);
386		assert_eq!(details.coin_type, "0x123");
387		assert_eq!(details.value, 100u128);
388	}
389
390	#[test]
391	fn test_payout_details() {
392		let details = PayoutDetails {
393			phase: Phase::default(),
394			topics: Topics::default(),
395			amount: 100u128,
396			receiver: "0x123".to_string(),
397		};
398		assert_eq!(details.amount, 100u128);
399		assert_eq!(details.receiver, "0x123");
400	}
401
402	#[test]
403	fn test_event_type_contract_call() {
404		let call_details = CallDetails {
405			phase: Phase::default(),
406			topics: Topics::default(),
407			address: "0x123".to_string(),
408			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
409				.to_string(),
410		};
411		let event_type = EventType::MidnightCallContract(call_details);
412
413		match event_type {
414			EventType::MidnightCallContract(details) => {
415				assert_eq!(
416					details.tx_hash,
417					"0x0000000000000000000000000000000000000000000000000000000000000000"
418				);
419				assert_eq!(details.address, "0x123");
420			}
421			_ => panic!("Expected MidnightCallContract event type"),
422		}
423	}
424
425	#[test]
426	fn test_event_type_contract_deploy() {
427		let deploy_details = DeploymentDetails {
428			phase: Phase::default(),
429			topics: Topics::default(),
430			address: "0x123".to_string(),
431			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
432				.to_string(),
433		};
434		let event_type = EventType::MidnightDeployContract(deploy_details);
435
436		match event_type {
437			EventType::MidnightDeployContract(details) => {
438				assert_eq!(
439					details.tx_hash,
440					"0x0000000000000000000000000000000000000000000000000000000000000000"
441				);
442				assert_eq!(details.address, "0x123");
443			}
444			_ => panic!("Expected MidnightDeployContract event type"),
445		}
446	}
447
448	#[test]
449	fn test_event_type_tx_applied() {
450		let tx_details = TxAppliedDetails {
451			phase: Phase::default(),
452			topics: Topics::default(),
453			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
454				.to_string(),
455		};
456		let event_type = EventType::MidnightTxApplied(tx_details);
457
458		match event_type {
459			EventType::MidnightTxApplied(details) => {
460				assert_eq!(
461					details.tx_hash,
462					"0x0000000000000000000000000000000000000000000000000000000000000000"
463				);
464			}
465			_ => panic!("Expected MidnightTxApplied event type"),
466		}
467	}
468
469	#[test]
470	fn test_event_deref() {
471		let tx_details = TxAppliedDetails {
472			phase: Phase::default(),
473			topics: Topics::default(),
474			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
475				.to_string(),
476		};
477		let event_type = EventType::MidnightTxApplied(tx_details);
478		let event = Event(event_type);
479
480		match &*event {
481			EventType::MidnightTxApplied(details) => {
482				assert_eq!(
483					details.tx_hash,
484					"0x0000000000000000000000000000000000000000000000000000000000000000"
485				);
486			}
487			_ => panic!("Expected MidnightTxApplied event type"),
488		}
489	}
490
491	#[test]
492	fn test_event_from_event_type() {
493		let tx_details = TxAppliedDetails {
494			phase: Phase::default(),
495			topics: Topics::default(),
496			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
497				.to_string(),
498		};
499		let event_type = EventType::MidnightTxApplied(tx_details);
500		let event = Event::from(event_type);
501
502		match &*event {
503			EventType::MidnightTxApplied(details) => {
504				assert_eq!(
505					details.tx_hash,
506					"0x0000000000000000000000000000000000000000000000000000000000000000"
507				);
508			}
509			_ => panic!("Expected MidnightTxApplied event type"),
510		}
511	}
512
513	#[test]
514	fn test_event_type_from_event() {
515		let tx_details = TxAppliedDetails {
516			phase: Phase::default(),
517			topics: Topics::default(),
518			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
519				.to_string(),
520		};
521		let event_type = EventType::MidnightTxApplied(tx_details);
522		let event = Event(event_type);
523		let converted_event_type = EventType::from(event);
524
525		match converted_event_type {
526			EventType::MidnightTxApplied(details) => {
527				assert_eq!(
528					details.tx_hash,
529					"0x0000000000000000000000000000000000000000000000000000000000000000"
530				);
531			}
532			_ => panic!("Expected MidnightTxApplied event type"),
533		}
534	}
535
536	#[test]
537	fn test_event_serialization() {
538		let tx_details = TxAppliedDetails {
539			phase: Phase::default(),
540			topics: Topics::default(),
541			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
542				.to_string(),
543		};
544		let event_type = EventType::MidnightTxApplied(tx_details);
545		let event = Event(event_type);
546
547		let serialized = serde_json::to_string(&event).unwrap();
548		let deserialized: Event = serde_json::from_str(&serialized).unwrap();
549
550		match &*deserialized {
551			EventType::MidnightTxApplied(details) => {
552				assert_eq!(
553					details.tx_hash,
554					"0x0000000000000000000000000000000000000000000000000000000000000000"
555				);
556			}
557			_ => panic!("Expected MidnightTxApplied event type"),
558		}
559	}
560
561	#[test]
562	fn test_event_from_value() {
563		// Test valid TxApplied event
564		let valid_json = json!({
565			"MidnightTxApplied": {
566				"phase": {
567					"ApplyExtrinsic": 0
568				},
569				"topics": { "topics": [] },
570				"tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
571			}
572		});
573		let event = Event::from(valid_json);
574		match &*event {
575			EventType::MidnightTxApplied(details) => {
576				assert_eq!(
577					details.tx_hash,
578					"0x0000000000000000000000000000000000000000000000000000000000000000"
579				);
580				assert_eq!(details.phase, Phase::ApplyExtrinsic(0));
581				assert_eq!(details.topics.topics, Vec::<String>::new());
582			}
583			_ => panic!("Expected MidnightTxApplied event type"),
584		}
585
586		// Test invalid event type
587		let invalid_json = json!({
588			"InvalidType": {
589				"some_field": "value"
590			}
591		});
592		let event = Event::from(invalid_json);
593		match &*event {
594			EventType::Unknown(_) => (),
595			_ => panic!("Expected Unknown event type"),
596		}
597
598		// Test malformed JSON
599		let malformed_json = json!({
600			"MidnightTxApplied": "not_an_object"
601		});
602		let event = Event::from(malformed_json);
603		match &*event {
604			EventType::Unknown(_) => (),
605			_ => panic!("Expected Unknown event type"),
606		}
607	}
608
609	#[test]
610	fn test_event_get_tx_hash() {
611		let tx_details = TxAppliedDetails {
612			phase: Phase::default(),
613			topics: Topics::default(),
614			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
615				.to_string(),
616		};
617		let event_type = EventType::MidnightTxApplied(tx_details);
618		let event = Event(event_type);
619		assert_eq!(
620			event.get_tx_hash(),
621			Some("0x0000000000000000000000000000000000000000000000000000000000000000".to_string())
622		);
623
624		let call_details = CallDetails {
625			phase: Phase::default(),
626			topics: Topics::default(),
627			address: "0x123".to_string(),
628			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
629				.to_string(),
630		};
631		let event_type = EventType::MidnightCallContract(call_details);
632		let event = Event(event_type);
633		assert_eq!(
634			event.get_tx_hash(),
635			Some("0x0000000000000000000000000000000000000000000000000000000000000000".to_string())
636		);
637
638		let deploy_details = DeploymentDetails {
639			phase: Phase::default(),
640			topics: Topics::default(),
641			address: "0x123".to_string(),
642			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
643				.to_string(),
644		};
645		let event_type = EventType::MidnightDeployContract(deploy_details);
646		let event = Event(event_type);
647		assert_eq!(
648			event.get_tx_hash(),
649			Some("0x0000000000000000000000000000000000000000000000000000000000000000".to_string())
650		);
651
652		let maintain_details = MaintainDetails {
653			phase: Phase::default(),
654			topics: Topics::default(),
655			address: "0x123".to_string(),
656			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
657				.to_string(),
658		};
659		let event_type = EventType::MidnightMaintainContract(maintain_details);
660		let event = Event(event_type);
661		assert_eq!(
662			event.get_tx_hash(),
663			Some("0x0000000000000000000000000000000000000000000000000000000000000000".to_string())
664		);
665
666		let claim_mint_details = ClaimMintDetails {
667			phase: Phase::default(),
668			topics: Topics::default(),
669			coin_type: "0x123".to_string(),
670			value: 100u128,
671			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
672				.to_string(),
673		};
674		let event_type = EventType::MidnightClaimMint(claim_mint_details);
675		let event = Event(event_type);
676		assert_eq!(
677			event.get_tx_hash(),
678			Some("0x0000000000000000000000000000000000000000000000000000000000000000".to_string())
679		);
680
681		let payout_details = PayoutDetails {
682			phase: Phase::default(),
683			topics: Topics::default(),
684			amount: 100u128,
685			receiver: "0x123".to_string(),
686		};
687		let event_type = EventType::MidnightPayoutMinted(payout_details);
688		let event = Event(event_type);
689		assert_eq!(event.get_tx_hash(), None);
690
691		let unknown_event = Event(EventType::Unknown("unknown".to_string()));
692		assert_eq!(unknown_event.get_tx_hash(), None);
693	}
694
695	#[test]
696	fn test_event_type_checks() {
697		// Test is_tx_applied
698		let tx_details = TxAppliedDetails {
699			phase: Phase::default(),
700			topics: Topics::default(),
701			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
702				.to_string(),
703		};
704		let event = Event(EventType::MidnightTxApplied(tx_details));
705		assert!(event.is_tx_applied());
706		assert!(!event.is_only_guaranteed_tx_applied());
707		assert!(event.is_success());
708
709		// Test is_only_guaranteed_tx_applied
710		let tx_details = TxAppliedDetails {
711			phase: Phase::default(),
712			topics: Topics::default(),
713			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
714				.to_string(),
715		};
716		let event = Event(EventType::MidnightOnlyGuaranteedTxApplied(tx_details));
717		assert!(!event.is_tx_applied());
718		assert!(event.is_only_guaranteed_tx_applied());
719		assert!(event.is_success());
720
721		// Test other event types
722		let call_details = CallDetails {
723			phase: Phase::default(),
724			topics: Topics::default(),
725			address: "0x123".to_string(),
726			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
727				.to_string(),
728		};
729		let event = Event(EventType::MidnightCallContract(call_details));
730		assert!(!event.is_tx_applied());
731		assert!(!event.is_only_guaranteed_tx_applied());
732		assert!(!event.is_success());
733
734		let deploy_details = DeploymentDetails {
735			phase: Phase::default(),
736			topics: Topics::default(),
737			address: "0x123".to_string(),
738			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
739				.to_string(),
740		};
741		let event = Event(EventType::MidnightDeployContract(deploy_details));
742		assert!(!event.is_tx_applied());
743		assert!(!event.is_only_guaranteed_tx_applied());
744		assert!(!event.is_success());
745
746		let maintain_details = MaintainDetails {
747			phase: Phase::default(),
748			topics: Topics::default(),
749			address: "0x123".to_string(),
750			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
751				.to_string(),
752		};
753		let event = Event(EventType::MidnightMaintainContract(maintain_details));
754		assert!(!event.is_tx_applied());
755		assert!(!event.is_only_guaranteed_tx_applied());
756		assert!(!event.is_success());
757
758		let payout_details = PayoutDetails {
759			phase: Phase::default(),
760			topics: Topics::default(),
761			amount: 100u128,
762			receiver: "0x123".to_string(),
763		};
764		let event = Event(EventType::MidnightPayoutMinted(payout_details));
765		assert!(!event.is_tx_applied());
766		assert!(!event.is_only_guaranteed_tx_applied());
767		assert!(!event.is_success());
768
769		let claim_mint_details = ClaimMintDetails {
770			phase: Phase::default(),
771			topics: Topics::default(),
772			coin_type: "0x123".to_string(),
773			value: 100u128,
774			tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
775				.to_string(),
776		};
777		let event = Event(EventType::MidnightClaimMint(claim_mint_details));
778		assert!(!event.is_tx_applied());
779		assert!(!event.is_only_guaranteed_tx_applied());
780		assert!(!event.is_success());
781
782		let event = Event(EventType::Unknown("unknown".to_string()));
783		assert!(!event.is_tx_applied());
784		assert!(!event.is_only_guaranteed_tx_applied());
785		assert!(!event.is_success());
786	}
787
788	#[test]
789	fn test_event_get_topics() {
790		let topics = vec!["topic1".to_string(), "topic2".to_string()];
791		let topics_struct = Topics {
792			topics: topics.clone(),
793		};
794
795		// Test TxApplied
796		let tx_details = TxAppliedDetails {
797			phase: Phase::default(),
798			topics: topics_struct.clone(),
799			tx_hash: "0x123".to_string(),
800		};
801		let event = Event(EventType::MidnightTxApplied(tx_details));
802		assert_eq!(event.get_topics(), Some(topics.clone()));
803
804		// Test OnlyGuaranteedTxApplied
805		let tx_details = TxAppliedDetails {
806			phase: Phase::default(),
807			topics: topics_struct.clone(),
808			tx_hash: "0x123".to_string(),
809		};
810		let event = Event(EventType::MidnightOnlyGuaranteedTxApplied(tx_details));
811		assert_eq!(event.get_topics(), Some(topics.clone()));
812
813		// Test CallContract
814		let call_details = CallDetails {
815			phase: Phase::default(),
816			topics: topics_struct.clone(),
817			address: "0x123".to_string(),
818			tx_hash: "0x456".to_string(),
819		};
820		let event = Event(EventType::MidnightCallContract(call_details));
821		assert_eq!(event.get_topics(), Some(topics.clone()));
822
823		// Test DeployContract
824		let deploy_details = DeploymentDetails {
825			phase: Phase::default(),
826			topics: topics_struct.clone(),
827			address: "0x123".to_string(),
828			tx_hash: "0x456".to_string(),
829		};
830		let event = Event(EventType::MidnightDeployContract(deploy_details));
831		assert_eq!(event.get_topics(), Some(topics.clone()));
832
833		// Test MaintainContract
834		let maintain_details = MaintainDetails {
835			phase: Phase::default(),
836			topics: topics_struct.clone(),
837			address: "0x123".to_string(),
838			tx_hash: "0x456".to_string(),
839		};
840		let event = Event(EventType::MidnightMaintainContract(maintain_details));
841		assert_eq!(event.get_topics(), Some(topics.clone()));
842
843		// Test PayoutMinted
844		let payout_details = PayoutDetails {
845			phase: Phase::default(),
846			topics: topics_struct.clone(),
847			amount: 100u128,
848			receiver: "0x123".to_string(),
849		};
850		let event = Event(EventType::MidnightPayoutMinted(payout_details));
851		assert_eq!(event.get_topics(), Some(topics.clone()));
852
853		// Test ClaimMint
854		let claim_mint_details = ClaimMintDetails {
855			phase: Phase::default(),
856			topics: topics_struct,
857			coin_type: "ETH".to_string(),
858			value: 100u128,
859			tx_hash: "0x456".to_string(),
860		};
861		let event = Event(EventType::MidnightClaimMint(claim_mint_details));
862		assert_eq!(event.get_topics(), Some(topics));
863
864		// Test Unknown
865		let event = Event(EventType::Unknown("unknown".to_string()));
866		assert_eq!(event.get_topics(), None);
867	}
868
869	#[test]
870	fn test_event_get_phase() {
871		let phase = Phase::ApplyExtrinsic(1);
872
873		// Test TxApplied
874		let tx_details = TxAppliedDetails {
875			phase: phase.clone(),
876			topics: Topics::default(),
877			tx_hash: "0x123".to_string(),
878		};
879		let event = Event(EventType::MidnightTxApplied(tx_details));
880		assert_eq!(event.get_phase(), Some(phase.clone()));
881
882		// Test OnlyGuaranteedTxApplied
883		let tx_details = TxAppliedDetails {
884			phase: phase.clone(),
885			topics: Topics::default(),
886			tx_hash: "0x123".to_string(),
887		};
888		let event = Event(EventType::MidnightOnlyGuaranteedTxApplied(tx_details));
889		assert_eq!(event.get_phase(), Some(phase.clone()));
890
891		// Test CallContract
892		let call_details = CallDetails {
893			phase: phase.clone(),
894			topics: Topics::default(),
895			address: "0x123".to_string(),
896			tx_hash: "0x456".to_string(),
897		};
898		let event = Event(EventType::MidnightCallContract(call_details));
899		assert_eq!(event.get_phase(), Some(phase.clone()));
900
901		// Test DeployContract
902		let deploy_details = DeploymentDetails {
903			phase: phase.clone(),
904			topics: Topics::default(),
905			address: "0x123".to_string(),
906			tx_hash: "0x456".to_string(),
907		};
908		let event = Event(EventType::MidnightDeployContract(deploy_details));
909		assert_eq!(event.get_phase(), Some(phase.clone()));
910
911		// Test MaintainContract
912		let maintain_details = MaintainDetails {
913			phase: phase.clone(),
914			topics: Topics::default(),
915			address: "0x123".to_string(),
916			tx_hash: "0x456".to_string(),
917		};
918		let event = Event(EventType::MidnightMaintainContract(maintain_details));
919		assert_eq!(event.get_phase(), Some(phase.clone()));
920
921		// Test PayoutMinted
922		let payout_details = PayoutDetails {
923			phase: phase.clone(),
924			topics: Topics::default(),
925			amount: 100u128,
926			receiver: "0x123".to_string(),
927		};
928		let event = Event(EventType::MidnightPayoutMinted(payout_details));
929		assert_eq!(event.get_phase(), Some(phase.clone()));
930
931		// Test ClaimMint
932		let claim_mint_details = ClaimMintDetails {
933			phase: phase.clone(),
934			topics: Topics::default(),
935			coin_type: "ETH".to_string(),
936			value: 100u128,
937			tx_hash: "0x456".to_string(),
938		};
939		let event = Event(EventType::MidnightClaimMint(claim_mint_details));
940		assert_eq!(event.get_phase(), Some(phase));
941
942		// Test Unknown
943		let event = Event(EventType::Unknown("unknown".to_string()));
944		assert_eq!(event.get_phase(), None);
945	}
946
947	#[test]
948	fn test_event_type_default() {
949		let default_event_type = EventType::default();
950		match default_event_type {
951			EventType::Unknown(message) => {
952				assert!(message.starts_with("Unknown event type: "));
953				assert!(message.contains("EventType"));
954			}
955			_ => panic!("Expected Unknown event type"),
956		}
957	}
958
959	#[test]
960	fn test_event_deref_mut() {
961		let mut event = Event(EventType::Unknown("original".to_string()));
962
963		// Test that we can modify the inner EventType through deref_mut
964		*event = EventType::Unknown("modified".to_string());
965
966		match &*event {
967			EventType::Unknown(message) => {
968				assert_eq!(message, "modified");
969			}
970			_ => panic!("Expected Unknown event type"),
971		}
972	}
973}