1use anyhow::Result;
4use async_trait::async_trait;
5use hypercall_types::WalletAddress;
6
7use crate::DatabaseHandler;
8
9#[async_trait]
10impl hypercall_db::RsmCreditReader for DatabaseHandler {
11 fn directive_outbox_exists_sync(&self, directive_id: &str) -> Result<bool> {
12 DatabaseHandler::directive_outbox_exists_sync(self, directive_id)
13 }
14
15 async fn get_max_rsm_deposit_credit_observed_block(&self) -> Result<Option<u64>> {
16 DatabaseHandler::get_max_rsm_deposit_credit_observed_block(self).await
17 }
18
19 fn get_exchange_cash_ledger_watermark_sync(&self) -> Result<Option<i64>> {
20 DatabaseHandler::get_exchange_cash_ledger_watermark_sync(self)
21 }
22
23 async fn get_option_instrument_for_credit(
24 &self,
25 token: &WalletAddress,
26 ) -> Result<Option<hypercall_db::OptionInstrumentForCredit>> {
27 DatabaseHandler::get_option_instrument_for_credit(self, token).await
28 }
29
30 async fn list_recent_cash_deposit_monitoring_rows(
31 &self,
32 limit: i64,
33 offset: i64,
34 ) -> Result<Vec<hypercall_db::DepositMonitoringRow>> {
35 DatabaseHandler::list_recent_cash_deposit_monitoring_rows(self, limit, offset).await
36 }
37}
38
39#[async_trait]
40impl hypercall_db::RsmCreditWriter for DatabaseHandler {
41 async fn ensure_observed_deposit_account(&self, account: &WalletAddress) -> Result<()> {
42 DatabaseHandler::ensure_observed_deposit_account(self, account).await
43 }
44
45 async fn claim_rsm_deposit_credit(
46 &self,
47 input: &hypercall_db::RsmDepositCreditClaimInput,
48 ) -> Result<hypercall_db::RsmDepositCreditClaimRecord> {
49 DatabaseHandler::claim_rsm_deposit_credit(self, input).await
50 }
51
52 async fn mark_rsm_deposit_credit_submitted(&self, request_id: &str) -> Result<()> {
53 DatabaseHandler::mark_rsm_deposit_credit_submitted(self, request_id).await
54 }
55
56 async fn mark_rsm_deposit_credit_failed(&self, request_id: &str, error: &str) -> Result<()> {
57 DatabaseHandler::mark_rsm_deposit_credit_failed(self, request_id, error).await
58 }
59
60 async fn pending_rsm_usdc_deposit_for_amount(
61 &self,
62 amount_wei: &str,
63 ) -> Result<Option<hypercall_db::RsmUsdcDepositMatch>> {
64 DatabaseHandler::pending_rsm_usdc_deposit_for_amount(self, amount_wei).await
65 }
66
67 async fn pending_rsm_usdc_deposit_for_evm_tx_hash(
68 &self,
69 evm_tx_hash: &str,
70 amount_wei: &str,
71 ) -> Result<Option<hypercall_db::RsmUsdcDepositMatch>> {
72 DatabaseHandler::pending_rsm_usdc_deposit_for_evm_tx_hash(self, evm_tx_hash, amount_wei)
73 .await
74 }
75
76 async fn pending_rsm_usdc_deposit_for_credited_hypercore_event(
77 &self,
78 event_hash: &str,
79 amount_wei: &str,
80 ) -> Result<Option<hypercall_db::RsmUsdcDepositMatch>> {
81 DatabaseHandler::pending_rsm_usdc_deposit_for_credited_hypercore_event(
82 self, event_hash, amount_wei,
83 )
84 .await
85 }
86
87 async fn credited_wallet_for_hypercore_cash_event(
88 &self,
89 event_hash: &str,
90 ) -> Result<Option<WalletAddress>> {
91 DatabaseHandler::credited_wallet_for_hypercore_cash_event(self, event_hash).await
92 }
93
94 async fn non_crediting_hypercore_cash_event(
95 &self,
96 event_hash: &str,
97 amount_usdc: rust_decimal::Decimal,
98 ) -> Result<bool> {
99 DatabaseHandler::non_crediting_hypercore_cash_event(self, event_hash, amount_usdc).await
100 }
101
102 async fn apply_hypercore_cash_deposit(
103 &self,
104 input: &hypercall_db::HypercoreCashLedgerApply,
105 ) -> Result<hypercall_db::HypercoreCashLedgerApplyResult> {
106 DatabaseHandler::apply_hypercore_cash_deposit(self, input).await
107 }
108
109 async fn record_hypercore_cash_deposit_pending_margin_mode(
110 &self,
111 input: &hypercall_db::HypercoreCashLedgerApply,
112 ) -> Result<()> {
113 DatabaseHandler::record_hypercore_cash_deposit_pending_margin_mode(self, input).await
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use diesel::sql_types::{BigInt, Binary, Text};
120 use diesel::RunQueryDsl;
121 use hypercall_db::RsmCreditReader;
122 use hypercall_types::WalletAddress;
123
124 use crate::test_helpers::TestDb;
125
126 fn wallet(byte: u8) -> WalletAddress {
127 WalletAddress::from([byte; 20])
128 }
129
130 #[tokio::test]
131 async fn rsm_credit_reader_lists_recent_cash_deposit_monitoring_rows() {
132 let db = TestDb::new().await.expect("test db");
133 let account = wallet(7);
134 let token = wallet(9);
135
136 {
137 let mut conn = db.handler.pool().get().expect("db connection");
138 diesel::sql_query(
139 "INSERT INTO rsm_deposit_credits
140 (tx_hash, log_index, observed_block, account, token, amount_wei, credit_kind,
141 request_id, status, created_at, updated_at)
142 VALUES ($1, $2, $3, $4, $5, $6, 'usdc', $7, 'submitted', now(), now())",
143 )
144 .bind::<Text, _>("0xmonitoringusdc")
145 .bind::<BigInt, _>(3_i64)
146 .bind::<BigInt, _>(42_i64)
147 .bind::<Binary, _>(account.as_bytes())
148 .bind::<Binary, _>(token.as_bytes())
149 .bind::<Text, _>("123450000")
150 .bind::<Text, _>("rsm-monitoring-usdc")
151 .execute(&mut conn)
152 .expect("insert rsm deposit credit");
153 }
154
155 let reader: &dyn RsmCreditReader = db.handler.as_ref();
156 let rows = reader
157 .list_recent_cash_deposit_monitoring_rows(10, 0)
158 .await
159 .expect("monitoring rows");
160
161 assert_eq!(rows.len(), 1);
162 let row = &rows[0];
163 assert_eq!(row.source, "exchange_usdc");
164 assert_eq!(row.status, "submitted");
165 assert_eq!(row.correlation_status, "writer_action_correlated");
166 assert_eq!(row.wallet, account);
167 assert_eq!(row.amount_usdc, "123.4500000000000000");
168 assert_eq!(row.event_hash, "0xmonitoringusdc");
169 assert_eq!(row.tx_hash.as_deref(), Some("0xmonitoringusdc"));
170 assert_eq!(row.request_id.as_deref(), Some("rsm-monitoring-usdc"));
171 assert_eq!(row.observed_block, Some(42));
172 assert_eq!(row.log_index, Some(3));
173 assert_eq!(row.ledger_event_id, None);
174 }
175}