1use uuid::Uuid;
2
3use super::{
4 finalized_receive_intent_by_quote_namespace, outpoint_to_key, BdkStorage,
5 FinalizedReceiveIntentRecord, BDK_NAMESPACE, FINALIZED_RECEIVE_INTENT_NAMESPACE,
6 FINALIZED_RECEIVE_INTENT_OUTPOINT_NAMESPACE, RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE,
7 RECEIVE_INTENT_NAMESPACE, RECEIVE_INTENT_OUTPOINT_NAMESPACE,
8};
9use crate::error::Error;
10use crate::receive::receive_intent::record::ReceiveIntentRecord;
11
12impl BdkStorage {
13 pub async fn track_receive_address(&self, address: &str, quote_id: &str) -> Result<(), Error> {
17 let mut tx = self
18 .kv_store
19 .begin_transaction()
20 .await
21 .map_err(Error::from)?;
22
23 tx.kv_write(
24 BDK_NAMESPACE,
25 RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE,
26 address,
27 quote_id.as_bytes(),
28 )
29 .await
30 .map_err(Error::from)?;
31
32 tx.commit().await.map_err(Error::from)?;
33 Ok(())
34 }
35
36 pub async fn get_quote_id_by_receive_address(
38 &self,
39 address: &str,
40 ) -> Result<Option<String>, Error> {
41 let quote_id_bytes = self
42 .kv_store
43 .kv_read(BDK_NAMESPACE, RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE, address)
44 .await
45 .map_err(Error::from)?;
46
47 let Some(quote_id_bytes) = quote_id_bytes else {
48 return Ok(None);
49 };
50
51 let quote_id = String::from_utf8(quote_id_bytes)
52 .map_err(|e| Error::Wallet(format!("Invalid quote-id index entry: {}", e)))?;
53 Ok(Some(quote_id))
54 }
55
56 pub async fn get_tracked_receive_addresses(&self) -> Result<Vec<String>, Error> {
58 self.kv_store
59 .kv_list(BDK_NAMESPACE, RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE)
60 .await
61 .map_err(Error::from)
62 }
63
64 pub async fn create_receive_intent_if_absent(
72 &self,
73 intent: &ReceiveIntentRecord,
74 ) -> Result<bool, Error> {
75 let outpoint = match &intent.state {
76 crate::receive::receive_intent::record::ReceiveIntentState::Detected {
77 outpoint,
78 ..
79 } => outpoint.clone(),
80 };
81
82 let mut tx = self
83 .kv_store
84 .begin_transaction()
85 .await
86 .map_err(Error::from)?;
87
88 let outpoint_key = outpoint_to_key(&outpoint);
90 let active = tx
91 .kv_read(
92 BDK_NAMESPACE,
93 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
94 &outpoint_key,
95 )
96 .await
97 .map_err(Error::from)?;
98
99 if active.is_some() {
100 tx.rollback().await.map_err(Error::from)?;
101 return Ok(false);
102 }
103
104 let finalized = tx
105 .kv_read(
106 BDK_NAMESPACE,
107 FINALIZED_RECEIVE_INTENT_OUTPOINT_NAMESPACE,
108 &outpoint_key,
109 )
110 .await
111 .map_err(Error::from)?;
112
113 if finalized.is_some() {
114 tx.rollback().await.map_err(Error::from)?;
115 return Ok(false);
116 }
117
118 let serialized = serde_json::to_vec(intent)?;
119 tx.kv_write(
120 BDK_NAMESPACE,
121 RECEIVE_INTENT_NAMESPACE,
122 &intent.intent_id.to_string(),
123 &serialized,
124 )
125 .await
126 .map_err(Error::from)?;
127 tx.kv_write(
128 BDK_NAMESPACE,
129 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
130 &outpoint_key,
131 intent.intent_id.to_string().as_bytes(),
132 )
133 .await
134 .map_err(Error::from)?;
135 tx.commit().await.map_err(Error::from)?;
136 Ok(true)
137 }
138
139 pub async fn get_receive_intent(
141 &self,
142 intent_id: &Uuid,
143 ) -> Result<Option<ReceiveIntentRecord>, Error> {
144 self.get_record::<ReceiveIntentRecord>(&intent_id.to_string())
145 .await
146 }
147
148 pub async fn get_all_receive_intents(&self) -> Result<Vec<ReceiveIntentRecord>, Error> {
150 self.list_records::<ReceiveIntentRecord>().await
151 }
152
153 #[cfg(test)]
155 pub async fn delete_receive_intent(&self, intent_id: &Uuid) -> Result<(), Error> {
156 let Some(intent) = self.get_receive_intent(intent_id).await? else {
157 return Ok(());
158 };
159
160 let outpoint_key = match &intent.state {
161 crate::receive::receive_intent::record::ReceiveIntentState::Detected {
162 outpoint,
163 ..
164 } => outpoint_to_key(outpoint),
165 };
166
167 let mut tx = self
168 .kv_store
169 .begin_transaction()
170 .await
171 .map_err(Error::from)?;
172 tx.kv_remove(
173 BDK_NAMESPACE,
174 RECEIVE_INTENT_NAMESPACE,
175 &intent_id.to_string(),
176 )
177 .await
178 .map_err(Error::from)?;
179 tx.kv_remove(
180 BDK_NAMESPACE,
181 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
182 &outpoint_key,
183 )
184 .await
185 .map_err(Error::from)?;
186 tx.commit().await.map_err(Error::from)?;
187 Ok(())
188 }
189
190 pub async fn finalize_receive_intent(
194 &self,
195 intent_id: &Uuid,
196 record: &FinalizedReceiveIntentRecord,
197 ) -> Result<(), Error> {
198 let Some(intent) = self.get_receive_intent(intent_id).await? else {
199 return Err(Error::ReceiveIntentNotFound(*intent_id));
200 };
201
202 let outpoint_key = match &intent.state {
203 crate::receive::receive_intent::record::ReceiveIntentState::Detected {
204 outpoint,
205 ..
206 } => outpoint_to_key(outpoint),
207 };
208
209 let serialized = serde_json::to_vec(record)?;
210 let mut tx = self
211 .kv_store
212 .begin_transaction()
213 .await
214 .map_err(Error::from)?;
215
216 tx.kv_write(
217 BDK_NAMESPACE,
218 FINALIZED_RECEIVE_INTENT_NAMESPACE,
219 &record.intent_id.to_string(),
220 &serialized,
221 )
222 .await
223 .map_err(Error::from)?;
224 tx.kv_write(
225 BDK_NAMESPACE,
226 FINALIZED_RECEIVE_INTENT_OUTPOINT_NAMESPACE,
227 &outpoint_key,
228 record.intent_id.to_string().as_bytes(),
229 )
230 .await
231 .map_err(Error::from)?;
232
233 let quote_ns = finalized_receive_intent_by_quote_namespace(&record.quote_id);
236 tx.kv_write(
237 BDK_NAMESPACE,
238 "e_ns,
239 &record.intent_id.to_string(),
240 record.intent_id.to_string().as_bytes(),
241 )
242 .await
243 .map_err(Error::from)?;
244
245 tx.kv_remove(
246 BDK_NAMESPACE,
247 RECEIVE_INTENT_NAMESPACE,
248 &intent_id.to_string(),
249 )
250 .await
251 .map_err(Error::from)?;
252 tx.kv_remove(
253 BDK_NAMESPACE,
254 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
255 &outpoint_key,
256 )
257 .await
258 .map_err(Error::from)?;
259 tx.commit().await.map_err(Error::from)?;
260 Ok(())
261 }
262
263 #[cfg(test)]
265 pub async fn get_finalized_receive_intent(
266 &self,
267 intent_id: &Uuid,
268 ) -> Result<Option<FinalizedReceiveIntentRecord>, Error> {
269 self.get_record::<FinalizedReceiveIntentRecord>(&intent_id.to_string())
270 .await
271 }
272
273 pub async fn get_finalized_receive_intents_by_quote_id(
280 &self,
281 quote_id: &str,
282 ) -> Result<Vec<FinalizedReceiveIntentRecord>, Error> {
283 let quote_ns = finalized_receive_intent_by_quote_namespace(quote_id);
284 let intent_id_keys = self
285 .kv_store
286 .kv_list(BDK_NAMESPACE, "e_ns)
287 .await
288 .map_err(Error::from)?;
289
290 let mut results = Vec::new();
291 for intent_id_key in intent_id_keys {
292 if let Some(record) = self
293 .get_record::<FinalizedReceiveIntentRecord>(&intent_id_key)
294 .await?
295 {
296 results.push(record);
297 }
298 }
299 Ok(results)
300 }
301}