1pub mod lightning;
2pub mod musig2;
3pub mod persistence;
4pub mod settlement;
5pub mod trust_policy;
6use async_trait::async_trait;
7pub use lightning::*;
8use serde::{Deserialize, Serialize};
9pub use settlement::*;
10use std::sync::{Arc, RwLock};
11use thiserror::Error;
12use tracing::info;
13pub use trust_policy::*;
14
15pub const VERSION: &str = env!("CARGO_PKG_VERSION");
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct BlockInfo {
20 pub hash: String,
21 pub height: u64,
22 pub timestamp: u64,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct TransactionInfo {
27 pub txid: String,
28 pub confirmations: u32,
29 pub block_hash: Option<String>,
30 pub block_height: Option<u64>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
34#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
35pub enum FeeBumpStrategy {
36 Rbf,
37 Cpfp,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
41#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
42pub enum MempoolTxStatus {
43 #[default]
44 Pending,
45 Stuck,
46 BumpBroadcasted,
47 GuardrailRejected,
48 Confirmed,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, Default)]
52pub struct TrackedMempoolTx {
53 pub txid: String,
54 pub first_seen_at: u64,
55 pub last_evaluated_at: Option<u64>,
56 pub last_bump_at: Option<u64>,
57 pub bump_attempts: u32,
58 pub current_fee_rate_sat_vb: u64,
59 pub target_fee_rate_sat_vb: Option<u64>,
60 pub replaceable: bool,
61 pub cpfp_eligible: bool,
62 #[serde(default)]
63 pub status: MempoolTxStatus,
64 pub last_bump_strategy: Option<FeeBumpStrategy>,
65 pub last_error: Option<String>,
66 pub replacement_txid: Option<String>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, Default)]
70pub struct ChainState {
71 pub height: u64,
72 pub status: String,
73 pub last_updated: u64,
74 pub last_sync_time: u64,
75 pub best_block_hash: String,
76 pub network: String,
77 pub epoch: Option<String>,
79 pub mode: Option<String>,
80 pub burn_block_height: Option<u64>,
81}
82
83#[derive(Debug, Default, Clone, Serialize, Deserialize)]
84pub struct Metrics {
85 pub health_requests: u64,
86 pub state_requests: u64,
87 pub metrics_requests: u64,
88 pub verification_requests: u64,
89 pub verification_success: u64,
90 pub verification_failure: u64,
91 pub total_requests: u64,
92 pub trust_policy_allow: u64,
93 pub trust_policy_block: u64,
94 pub treasury_balance_stx: f64,
96 pub treasury_balance_btc: u64,
97 pub last_treasury_update: u64,
98 pub sbtc_liquidity: f64,
100 pub syi_index: f64,
101 pub fx_rmb_usd: f64,
103 pub fx_rub_usd: f64,
104 pub fx_inr_usd: f64,
105 pub fx_aed_usd: f64,
106 pub bounty_payouts_enabled: bool,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize, Default)]
111pub struct GatewayState {
112 pub bitcoin: ChainState,
113 pub stacks: ChainState,
114 pub metrics: Metrics,
115 pub wallets: SystemWallets,
116 pub handoff_state: HandoffState,
117 pub start_time: u64,
118}
119
120impl GatewayState {
121 pub fn new() -> Self {
122 Self {
123 bitcoin: ChainState::default(),
124 stacks: ChainState::default(),
125 metrics: Metrics::default(),
126 wallets: SystemWallets::default(),
127 handoff_state: HandoffState::default(),
128 start_time: std::time::SystemTime::now()
129 .duration_since(std::time::UNIX_EPOCH)
130 .unwrap()
131 .as_secs(),
132 }
133 }
134}
135
136pub type ConxianResult<T> = Result<T, ConxianError>;
137
138#[derive(Error, Debug)]
139pub enum ConxianError {
140 #[error("Bitcoin error: {0}")]
141 Bitcoin(String),
142 #[error("Stacks error: {0}")]
143 Stacks(String),
144 #[error("API error: {0}")]
145 Api(String),
146 #[error("Compliance error: {0}")]
147 Compliance(String),
148 #[error("Internal error: {0}")]
149 Internal(String),
150 #[error("Security/Verification error: {0}")]
151 Security(String),
152 #[error("IO error: {0}")]
153 Io(String),
154 #[error("Persistence error: {0}")]
155 Persistence(String),
156 #[error("Machine identity error: {0}")]
157 MachineIdentity(String),
158}
159
160pub type SharedState = Arc<RwLock<GatewayState>>;
162
163#[derive(Debug, Serialize, Deserialize, Clone)]
165pub struct Attestation {
166 pub device_id: String,
167 pub signature: String, pub payload: String,
169 pub public_key: String, }
171
172#[derive(Debug, Serialize, Deserialize, Clone)]
174pub struct SchnorrAttestation {
175 pub device_id: String,
176 pub signature: String, pub payload: String,
178 pub x_only_public_key: String, }
180
181#[derive(Debug, Serialize, Deserialize, Clone)]
183pub struct ZkmlProof {
184 pub device_id: String,
185 #[serde(default)]
186 pub image_id: String,
187 #[serde(default)]
188 pub receipt: String,
189 pub receipt_hash: String,
190 pub public_inputs: String,
191 pub journal: String,
192}
193
194#[derive(Debug, Serialize, Deserialize, Clone)]
196pub struct BitVmAttestation {
197 pub prover_id: String,
198 pub commitment_hash: String,
199 pub state_root: String,
200 #[serde(default)]
201 pub proof_hash: String,
202 #[serde(default)]
203 pub verifier_address: String,
204}
205
206#[derive(Debug, Serialize, Deserialize, Clone)]
208#[serde(tag = "type", content = "data")]
209pub enum AttestationRequest {
210 Ecdsa(Attestation),
211 Schnorr(SchnorrAttestation),
212 Zkml(ZkmlProof),
213 BitVm(BitVmAttestation),
214 Cbtc(CbtcAttestation),
215}
216
217#[derive(Debug, Serialize, Deserialize, Clone)]
223pub struct CbtcAttestation {
224 pub canton_domain: String,
226 pub contract_id: String,
228 pub amount_sats: u64,
230 pub bitcoin_utxos: Vec<String>,
232 #[serde(default)]
234 pub frost_attestation: Option<String>,
235 pub attested_at_height: u64,
237 #[serde(default)]
239 pub quorum: Option<CbtcQuorum>,
240}
241
242#[derive(Debug, Serialize, Deserialize, Clone)]
244pub struct CbtcQuorum {
245 pub signers_present: u16,
247 pub signers_total: u16,
249 pub aggregate_key: String,
251}
252
253#[derive(Debug, Serialize, Deserialize, Clone)]
255pub struct CbtcVerificationRequest {
256 pub attestation: CbtcAttestation,
258 #[serde(default)]
260 pub verify_utxo_proofs: bool,
261}
262
263#[derive(Debug, Serialize, Deserialize, Clone)]
265pub struct CbtcVerificationResponse {
266 pub verified: bool,
268 pub contract_id: String,
270 pub amount_sats: u64,
272 pub utxos_verified: u32,
274 pub quorum_ratio: Option<f64>,
276 pub verified_at: u64,
278 #[serde(default)]
280 pub checks: Vec<CbtcVerificationCheck>,
281}
282
283#[derive(Debug, Serialize, Deserialize, Clone)]
285pub struct CbtcVerificationCheck {
286 pub check: String,
288 pub passed: bool,
290 #[serde(default)]
292 pub detail: Option<String>,
293}
294
295#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
301pub struct UniversalContractRef {
302 pub ledger: String,
304 pub contract_id: String,
306 #[serde(default)]
308 pub domain: Option<String>,
309}
310
311#[derive(Debug, Serialize, Deserialize, Clone)]
313pub struct CantonDomainRef {
314 pub domain_name: String,
316 #[serde(default)]
318 pub synchronizer_endpoint: Option<String>,
319 #[serde(default)]
321 pub public_observer: bool,
322}
323
324#[derive(Debug, Serialize, Deserialize, Clone)]
327pub struct CantonStateTranslationRequest {
328 pub domain: CantonDomainRef,
330 pub daml_contract_id: String,
332 #[serde(default)]
334 pub template_name: Option<String>,
335 pub target_ledger: String,
337}
338
339#[derive(Debug, Serialize, Deserialize, Clone)]
341pub struct CantonStateTranslationResponse {
342 pub contract_ref: UniversalContractRef,
344 pub source_ledger: String,
346 pub target_ledger: String,
348 pub translation_complete: bool,
350 #[serde(default)]
352 pub unmapped_fields: Vec<String>,
353 pub translated_at: u64,
355}
356
357#[derive(Debug, Serialize, Deserialize, Clone)]
363pub struct CcipMessageRoute {
364 pub source_chain: String,
366 pub destination_chain: String,
368 pub message_id: String,
370 pub payload: String,
372 #[serde(default)]
374 pub requires_screening: bool,
375}
376
377#[derive(Debug, Serialize, Deserialize, Clone)]
379pub struct CcipRouteRequest {
380 pub message: CcipMessageRoute,
382 #[serde(default)]
384 pub elevated_scrutiny: bool,
385}
386
387#[derive(Debug, Serialize, Deserialize, Clone)]
389pub struct CcipRouteResponse {
390 pub approved: bool,
392 pub message_id: String,
394 pub risk_level: SanctionsRisk,
396 #[serde(default)]
398 pub rejection_reason: Option<String>,
399 #[serde(default)]
401 pub audit_ref: Option<String>,
402 pub routed_at: u64,
404}
405
406#[derive(Debug, Serialize, Deserialize, Clone)]
411pub struct MachineRwaRevenue {
412 pub machine_identity: MachineIdentity,
414 pub period_start: u64,
416 pub period_end: u64,
418 pub total_revenue_minor: u64,
420 pub currency: String,
422 #[serde(default)]
424 pub revenue_sources: Vec<RevenueSource>,
425 #[serde(default)]
427 pub attestation_signature: Option<String>,
428}
429
430#[derive(Debug, Serialize, Deserialize, Clone)]
432pub struct RevenueSource {
433 pub service_type: MachineService,
435 pub amount_minor: u64,
437 #[serde(default)]
439 pub event_count: u64,
440 #[serde(default)]
442 pub metadata: Option<serde_json::Value>,
443}
444
445#[derive(Debug, Serialize, Deserialize, Clone)]
447pub struct MachineRwaVerificationRequest {
448 pub revenue: MachineRwaRevenue,
450 #[serde(default)]
452 pub verify_signature: bool,
453 #[serde(default)]
455 pub rwa_token_contract: Option<String>,
456}
457
458#[derive(Debug, Serialize, Deserialize, Clone)]
460pub struct MachineRwaVerificationResponse {
461 pub verified: bool,
463 pub machine_did: Option<String>,
465 pub verified_revenue_minor: u64,
467 pub currency: String,
469 pub period_start: u64,
471 pub period_end: u64,
472 pub sources_verified: u32,
474 #[serde(default)]
476 pub holder_distribution_bps: Option<u16>,
477 pub verified_at: u64,
479 #[serde(default)]
481 pub checks: Vec<RevenueVerificationCheck>,
482}
483
484#[derive(Debug, Serialize, Deserialize, Clone)]
486pub struct RevenueVerificationCheck {
487 pub check: String,
488 pub passed: bool,
489 #[serde(default)]
490 pub detail: Option<String>,
491}
492
493#[derive(Debug, Serialize, Deserialize, Clone)]
494pub struct JobCardSettlementRequest {
495 pub job_card: ConxianJobCard,
496 pub bitvm_attestation: BitVmAttestation,
497}
498
499#[derive(Debug, Serialize, Deserialize, Clone)]
501pub struct DlcBond {
502 pub bond_id: String,
503 pub amount_btc: u64,
504 pub interest_rate: f64,
505 pub maturity_date: u64,
506 pub sovereign_alignment: bool,
507}
508
509pub trait DlcOrchestrator: Send + Sync {
511 fn create_dlc_bond(&self, bond: &DlcBond) -> ConxianResult<String>;
512 fn settle_coupon(&self, bond_id: &str, amount_sbtc: u64) -> ConxianResult<bool>;
513}
514
515pub struct DlcManager {
517 pub oracle_pubkey: String,
518}
519
520impl DlcManager {
521 pub fn new(oracle_pubkey: String) -> Self {
522 Self { oracle_pubkey }
523 }
524}
525
526impl DlcOrchestrator for DlcManager {
527 fn create_dlc_bond(&self, bond: &DlcBond) -> ConxianResult<String> {
528 info!("Creating DLC-backed Bitcoin bond: {} sBTC", bond.amount_btc);
529 let bond_id = format!("dlc-bond-{}", uuid::Uuid::new_v4());
530 Ok(bond_id)
531 }
532
533 fn settle_coupon(&self, bond_id: &str, amount_sbtc: u64) -> ConxianResult<bool> {
534 info!(
535 "Settling coupon for DLC bond {}: {} satoshis",
536 bond_id, amount_sbtc
537 );
538 Ok(!bond_id.is_empty())
539 }
540}
541
542#[derive(Debug, Serialize, Deserialize, Clone)]
544pub struct IdentityResolutionRequest {
545 pub identifier: String,
546 pub provider: String, pub signature: Option<String>,
548}
549
550#[derive(Debug, Serialize, Deserialize, Clone)]
552pub struct IdentityResolutionResponse {
553 pub address: String,
554 pub provider: String,
555 pub verified: bool,
556 pub metadata: Option<serde_json::Value>,
557}
558
559#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
563#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
564pub enum MachineType {
565 ElectricVehicle,
566 EvCharger,
567 Drone,
568 Robot,
569 Sensor,
570 ComputeNode,
571 StorageNode,
572 Camera,
573 DeliveryVehicle,
574 EnergyMeter,
575 Other,
576}
577
578#[derive(Debug, Serialize, Deserialize, Clone)]
581pub struct MachineIdentity {
582 pub peaq_did: Option<String>,
584 pub dimo_vehicle_id: Option<String>,
586 pub device_key: String,
588 #[serde(default)]
590 pub attestation_proof: Option<String>,
591 pub machine_type: MachineType,
593 #[serde(default)]
595 pub label: Option<String>,
596}
597
598#[derive(Debug, Serialize, Deserialize, Clone)]
601pub struct MachineIdentityResolutionRequest {
602 pub identifier: String,
604 pub provider: String,
606 #[serde(default)]
608 pub signature: Option<String>,
609 #[serde(default)]
611 pub device_key: Option<String>,
612 #[serde(default)]
614 pub machine_type_hint: Option<MachineType>,
615}
616
617#[derive(Debug, Serialize, Deserialize, Clone)]
619pub struct MachineIdentityResolutionResponse {
620 pub identity: MachineIdentity,
622 pub provider: String,
624 pub verified: bool,
626 #[serde(default)]
628 pub metadata: Option<serde_json::Value>,
629}
630
631#[derive(Debug, Serialize, Deserialize, Clone)]
633pub struct GcpTokenRequest {
634 pub audience: String,
635 #[serde(default)]
636 pub grant_type: String,
637 #[serde(default)]
638 pub requested_token_type: String,
639 #[serde(default)]
640 pub scope: String,
641 pub subject_token: String,
642 #[serde(default)]
643 pub subject_token_type: String,
644}
645
646#[derive(Debug, Serialize, Deserialize, Clone, Default)]
648pub struct PersistentState {
649 pub bitcoin_height: u64,
650 pub stacks_height: u64,
651 #[serde(default)]
652 pub mempool_pending_txs: Vec<TrackedMempoolTx>,
653}
654
655pub trait Persistence: Send + Sync {
657 fn save(&self, state: &PersistentState) -> ConxianResult<()>;
658 fn load(&self) -> ConxianResult<PersistentState>;
659}
660
661#[derive(Debug, Serialize, Deserialize, Clone)]
663pub struct SystemWallets {
664 pub bootstrap: String,
665 pub treasury: String,
666 pub payout: String,
667 pub deployment: String,
668 pub emergency: String,
669 pub dao_handoff: String,
670 pub protocol_owned: String,
671 pub reserve_fund: String,
672 pub labs_ops: String,
673 pub contributor_claims: String,
674 pub founder_vault: String,
675}
676
677impl Default for SystemWallets {
678 fn default() -> Self {
679 Self {
680 bootstrap: "SPSZXAKV7DWTDZN2601WR31BM51BD3YTQWE97VRM".to_string(),
681 treasury: "SP12JZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
682 payout: "SP2JZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
683 deployment: "SP3JZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
684 emergency: "SP000000000000000000002Q6VF78".to_string(),
685 dao_handoff: "SP1P74G56Z5SNC6B2H70MBN8D6X1XW19C52R0P95".to_string(),
686 protocol_owned: "SP2JZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
687 reserve_fund: "SP3JZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
688 labs_ops: "SP2KZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
689 contributor_claims: "SP3KZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
690 founder_vault: "SP4KZZSBY0S3FJH7WJT2787YTYT8Y6725F7T8E62".to_string(),
691 }
692 }
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize)]
697pub struct AlexSwapRequest {
698 pub token_x: String,
699 pub token_y: String,
700 pub factor: u64,
701 pub amount: u128,
702 pub min_dy: Option<u128>,
703}
704
705#[derive(Debug, Serialize, Deserialize, Clone)]
707pub struct OfflineReceipt {
708 pub receipt_id: String,
709 pub tx_hash: String,
710 pub amount_sbtc: u64,
711 pub timestamp: u64,
712 pub device_id: String,
713 pub tee_signature: String, pub passkey_attestation: AttestationRequest,
715 pub status: OfflineReceiptStatus,
716}
717
718#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
719#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
720pub enum OfflineReceiptStatus {
721 Pending,
722 Gossiped,
723 Broadcasted,
724 Reconciled,
725}
726
727pub trait OfflineQueue: Send + Sync {
729 fn enqueue(&self, receipt: &OfflineReceipt) -> ConxianResult<()>;
730 fn dequeue_pending(&self) -> ConxianResult<Vec<OfflineReceipt>>;
731 fn mark_broadcasted(&self, receipt_id: &str) -> ConxianResult<()>;
732 fn claim_replay_key(&self, replay_key: &str, ttl_seconds: u64) -> ConxianResult<bool>;
737}
738
739#[derive(Debug, Serialize, Deserialize, Clone)]
741pub struct ConxianJobCard {
742 #[serde(rename = "@context", default)]
743 pub context: String,
744 #[serde(rename = "@type")]
745 pub r#type: String,
746 #[serde(default)]
747 pub work_intent: WorkIntent,
748}
749
750#[derive(Debug, Serialize, Deserialize, Clone, Default)]
751pub struct WorkIntent {
752 pub sender_address: String,
753 pub receiver_address: String,
754 pub amount_sbtc: u64,
755 pub town_name: Option<String>,
756 pub country_code: Option<String>,
757}
758
759#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
760pub enum RolloutMode {
761 Disabled,
762 Shadow,
763 Active,
764}
765
766#[derive(Debug, Serialize, Deserialize, Clone)]
767pub struct RgbAdapterConfig {
768 pub mode: RolloutMode,
769 pub node_url: String,
770}
771
772#[derive(Debug, Serialize, Deserialize, Clone)]
773pub struct ContractState {
774 pub contract_id: String,
775 pub schema_id: String,
776 pub state_data: serde_json::Value,
777}
778
779#[async_trait]
780pub trait RgbAdapter: Send + Sync {
781 async fn lookup_contract(&self, contract_id: &str) -> ConxianResult<Option<ContractState>>;
782 async fn verify_transition(&self, transition_id: &str) -> ConxianResult<bool>;
783}
784pub trait PersistentStateTrait: Send + Sync {
785 fn save(&self, state: &GatewayState) -> ConxianResult<()>;
786 fn load(&self) -> ConxianResult<GatewayState>;
787}
788
789#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default)]
791pub enum HandoffState {
792 #[default]
793 BootstrapActive,
794 SabAuditInProgress,
795 DaoProposalActive,
796 HandoffComplete,
797}
798
799impl SystemWallets {
800 pub fn get_payout_destination(&self, state: HandoffState) -> &str {
801 match state {
802 HandoffState::BootstrapActive => &self.bootstrap,
803 _ => &self.payout,
804 }
805 }
806
807 pub fn get_treasury_destination(&self, state: HandoffState) -> &str {
808 match state {
809 HandoffState::BootstrapActive => &self.bootstrap,
810 _ => &self.treasury,
811 }
812 }
813}
814
815#[async_trait]
816#[async_trait]
817#[async_trait]
818pub trait ChainAdapter: Send + Sync {
819 async fn get_latest_height(&self) -> ConxianResult<u64>;
820 async fn get_chain_identity(&self) -> String;
821 async fn prepare_unsigned_transaction(
822 &self,
823 tx_details: serde_json::Value,
824 ) -> ConxianResult<serde_json::Value>;
825 async fn verify_state_proof(&self, proof_metadata: serde_json::Value) -> ConxianResult<bool>;
826}
827
828#[async_trait]
829#[allow(async_fn_in_trait)]
830pub trait Bip322Verifier: Send + Sync {
831 fn verify_message(&self, address: &str, message: &str, signature: &str) -> ConxianResult<bool>;
832}
833
834#[async_trait]
835#[allow(async_fn_in_trait)]
836pub trait SimulatedStacksRpcTrait: Send + Sync {
837 async fn call_read_only(
838 &self,
839 contract: &str,
840 function: &str,
841 args: Vec<serde_json::Value>,
842 ) -> ConxianResult<serde_json::Value>;
843}
844
845#[derive(Debug, Serialize, Deserialize, Clone)]
847pub struct ReleaseApprovalRequest {
848 pub release_id: String,
849 pub artifact_hash: String,
850 pub environment: String,
851 pub requester: String,
852}
853
854#[derive(Debug, Serialize, Deserialize, Clone)]
856pub struct ReleaseDecisionRequest {
857 pub release_id: String,
858 pub decision: String, pub approver: String,
860 pub reason: Option<String>,
861}
862
863#[derive(Debug, Serialize, Deserialize, Clone)]
865pub struct GovernanceDecisionRequest {
866 pub proposal_id: String,
867 pub decision: String, pub voter: String,
869 pub signature: String, }
871
872#[derive(Debug, Serialize, Deserialize, Clone)]
874pub struct AdminActionResponse {
875 pub action_id: String,
876 pub status: String,
877 pub audit_event_id: String,
878 pub message: String,
879}
880
881#[derive(Debug, Serialize, Deserialize, Clone)]
883pub struct GovernanceAction {
884 pub action_id: String,
885 pub proposal_id: String,
886 pub action_type: String, pub payload: serde_json::Value,
888 pub status: String,
889 pub enacted_at: Option<u64>,
890}
891
892#[derive(Debug, Serialize, Deserialize, Clone)]
894pub struct TreasuryEvent {
895 pub event_id: String,
896 pub asset: String,
897 pub amount: u128,
898 pub direction: String, pub reason: String,
900 pub timestamp: u64,
901 pub reference_id: Option<String>,
902}
903
904#[derive(Debug, Serialize, Deserialize, Clone)]
906pub struct AuditEvent {
907 pub event_id: String,
908 pub domain: String, pub actor: String,
910 pub action: String,
911 pub outcome: String,
912 pub timestamp: u64,
913 pub metadata: serde_json::Value,
914}