Skip to main content

hypercall_db/types/
directive_outbox.rs

1//! Directive outbox persistence types and deposit/withdrawal domain types.
2
3use alloy::primitives::Address;
4use hypercall_types::directives::ActionKey;
5use hypercall_types::WalletAddress;
6use rust_decimal::Decimal;
7use serde::{Deserialize, Serialize};
8use sha3::{Digest, Keccak256};
9
10/// Recent deposit attribution row for admin monitoring.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct DepositMonitoringRow {
13    pub source: String,
14    pub status: String,
15    pub correlation_status: String,
16    pub wallet: WalletAddress,
17    pub amount_usdc: String,
18    pub event_hash: String,
19    pub tx_hash: Option<String>,
20    pub request_id: Option<String>,
21    pub observed_block: Option<i64>,
22    pub log_index: Option<i64>,
23    pub ledger_event_id: Option<i64>,
24    pub created_at: String,
25    pub updated_at: String,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
29pub enum DirectiveOutboxKind {
30    NeedsRsmSignature,
31    UserSignedDirective,
32}
33
34impl DirectiveOutboxKind {
35    pub fn as_str(&self) -> &'static str {
36        match self {
37            Self::NeedsRsmSignature => "needs_rsm_signature",
38            Self::UserSignedDirective => "user_signed_directive",
39        }
40    }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
44pub enum DirectiveDomainStatus {
45    Accepted,
46    Rejected,
47    PendingChainEffect,
48    Completed,
49    Failed,
50}
51
52impl DirectiveDomainStatus {
53    pub fn as_str(&self) -> &'static str {
54        match self {
55            Self::Accepted => "accepted",
56            Self::Rejected => "rejected",
57            Self::PendingChainEffect => "pending_chain_effect",
58            Self::Completed => "completed",
59            Self::Failed => "failed",
60        }
61    }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
65pub enum DirectiveDeliveryStatus {
66    Pending,
67    Broadcasted,
68    Included,
69    Finalized,
70    Reverted,
71    Expired,
72    DeadLettered,
73}
74
75impl DirectiveDeliveryStatus {
76    pub fn as_str(&self) -> &'static str {
77        match self {
78            Self::Pending => "pending",
79            Self::Broadcasted => "broadcasted",
80            Self::Included => "included",
81            Self::Finalized => "finalized",
82            Self::Reverted => "reverted",
83            Self::Expired => "expired",
84            Self::DeadLettered => "dead_lettered",
85        }
86    }
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct DirectiveOutboxAppend {
91    pub directive_id: String,
92    pub kind: DirectiveOutboxKind,
93    pub action_key: ActionKey,
94    pub wallet: WalletAddress,
95    pub account: WalletAddress,
96    pub signer: WalletAddress,
97    pub nonce: u64,
98    pub idempotency_key: String,
99    pub payload_hash: [u8; 32],
100    pub payload: Vec<u8>,
101    pub domain_status: DirectiveDomainStatus,
102    pub delivery_status: DirectiveDeliveryStatus,
103    pub created_ts_ms: u64,
104    pub expires_at_ms: Option<u64>,
105}
106
107impl DirectiveOutboxAppend {
108    pub fn needs_rsm_signature(
109        directive_id: String,
110        action_key: ActionKey,
111        wallet: WalletAddress,
112        account: WalletAddress,
113        signer: WalletAddress,
114        nonce: u64,
115        idempotency_key: String,
116        payload: Vec<u8>,
117        created_ts_ms: u64,
118        expires_at_ms: Option<u64>,
119    ) -> Self {
120        let payload_hash: [u8; 32] = Keccak256::digest(&payload).into();
121        Self {
122            directive_id,
123            kind: DirectiveOutboxKind::NeedsRsmSignature,
124            action_key,
125            wallet,
126            account,
127            signer,
128            nonce,
129            idempotency_key,
130            payload_hash,
131            payload,
132            domain_status: DirectiveDomainStatus::PendingChainEffect,
133            delivery_status: DirectiveDeliveryStatus::Pending,
134            created_ts_ms,
135            expires_at_ms,
136        }
137    }
138}
139
140/// Lightweight read-only projection for directive status queries.
141#[derive(Debug, Clone)]
142pub struct DirectiveStatusRow {
143    pub directive_id: String,
144    pub action_key: String,
145    pub domain_status: String,
146    pub delivery_status: String,
147    pub submitter_address: Option<Address>,
148    pub submitter_nonce: Option<u64>,
149    pub tx_hash: Option<String>,
150    pub created_ts_ms: Option<i64>,
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub struct DirectiveOutboxDeliveryMetricsRow {
155    pub action_key: String,
156    pub delivery_status: String,
157    pub pending_count: i64,
158    pub retrying_count: i64,
159    pub oldest_created_age_seconds: i64,
160    pub oldest_attempt_age_seconds: i64,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct DirectiveOutboxRecentRow {
165    pub outbox_seq: i64,
166    pub directive_id: String,
167    pub kind: String,
168    pub action_key: String,
169    pub wallet_address: WalletAddress,
170    pub account_address: WalletAddress,
171    pub signer_address: WalletAddress,
172    pub directive_nonce: i64,
173    pub domain_status: String,
174    pub delivery_status: String,
175    pub submitter_address: Option<Address>,
176    pub submitter_nonce: Option<u64>,
177    pub tx_hash: Option<String>,
178    pub delivery_attempts: i64,
179    pub last_delivery_error: Option<String>,
180    pub created_ts_ms: i64,
181    pub last_attempt_ts_ms: Option<i64>,
182    pub expires_at_ms: Option<i64>,
183}
184
185#[derive(Debug, Clone)]
186pub struct DirectiveOutboxRow {
187    pub outbox_seq: i64,
188    pub directive_id: String,
189    pub kind: String,
190    pub action_key: ActionKey,
191    pub account: WalletAddress,
192    pub signer: WalletAddress,
193    pub nonce: u64,
194    pub payload: Vec<u8>,
195    pub expires_at_ms: Option<u64>,
196}
197
198// ===== Deposit / withdrawal domain types =====
199
200#[derive(Debug, Clone, PartialEq, Eq)]
201pub struct RsmDepositCreditClaimInput {
202    pub tx_hash: String,
203    pub log_index: i64,
204    pub observed_block: i64,
205    pub account: WalletAddress,
206    pub token: WalletAddress,
207    pub amount_wei: String,
208    pub credit_kind: String,
209    pub request_id: String,
210}
211
212#[derive(Debug, Clone, PartialEq, Eq)]
213pub struct RsmDepositCreditClaimRecord {
214    pub tx_hash: String,
215    pub log_index: i64,
216    pub observed_block: i64,
217    pub account: WalletAddress,
218    pub token: WalletAddress,
219    pub amount_wei: String,
220    pub credit_kind: String,
221    pub request_id: String,
222    pub status: String,
223}
224
225#[derive(Debug, Clone, PartialEq, Eq)]
226pub struct RsmUsdcDepositMatch {
227    pub request_id: String,
228    pub account: WalletAddress,
229    pub tx_hash: String,
230    pub log_index: i64,
231    pub amount_wei: String,
232    pub token: WalletAddress,
233}
234
235#[derive(Debug, Clone, PartialEq, Eq)]
236pub struct HypercoreCashLedgerApply {
237    pub wallet: WalletAddress,
238    pub event_hash: String,
239    pub event_time_ms: i64,
240    pub amount_usdc: Decimal,
241}
242
243#[derive(Debug, Clone, PartialEq, Eq)]
244pub struct HypercoreCashLedgerApplyResult {
245    pub applied: bool,
246    pub balance_after: Option<Decimal>,
247    pub ledger_event_id: Option<u64>,
248}
249
250#[derive(Debug, Clone, PartialEq, Eq)]
251pub struct OptionInstrumentForCredit {
252    pub symbol: String,
253    pub underlying: String,
254    pub expiry: i64,
255    pub strike: Decimal,
256    pub option_type: String,
257}