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(
22 &self,
23 address: &str,
24 quote_id: &str,
25 ) -> Result<bool, Error> {
26 let mut tx = self
27 .kv_store
28 .begin_transaction()
29 .await
30 .map_err(Error::from)?;
31
32 let reserved = tx
35 .kv_write_if_absent(
36 BDK_NAMESPACE,
37 RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE,
38 address,
39 quote_id.as_bytes(),
40 )
41 .await
42 .map_err(Error::from)?;
43
44 if !reserved {
45 let existing = tx
46 .kv_read(BDK_NAMESPACE, RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE, address)
47 .await
48 .map_err(Error::from)?;
49 let same_quote = existing.as_deref() == Some(quote_id.as_bytes());
50 tx.rollback().await.map_err(Error::from)?;
51 return Ok(same_quote);
52 }
53
54 tx.commit().await.map_err(Error::from)?;
55 Ok(true)
56 }
57
58 pub async fn get_quote_id_by_receive_address(
60 &self,
61 address: &str,
62 ) -> Result<Option<String>, Error> {
63 let quote_id_bytes = self
64 .kv_store
65 .kv_read(BDK_NAMESPACE, RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE, address)
66 .await
67 .map_err(Error::from)?;
68
69 let Some(quote_id_bytes) = quote_id_bytes else {
70 return Ok(None);
71 };
72
73 let quote_id = String::from_utf8(quote_id_bytes)
74 .map_err(|e| Error::Wallet(format!("Invalid quote-id index entry: {}", e)))?;
75 Ok(Some(quote_id))
76 }
77
78 pub async fn get_tracked_receive_addresses(&self) -> Result<Vec<String>, Error> {
80 self.kv_store
81 .kv_list(BDK_NAMESPACE, RECEIVE_ADDRESS_QUOTE_ID_NAMESPACE)
82 .await
83 .map_err(Error::from)
84 }
85
86 pub async fn create_receive_intent_if_absent(
94 &self,
95 intent: &ReceiveIntentRecord,
96 ) -> Result<bool, Error> {
97 let outpoint = match &intent.state {
98 crate::receive::receive_intent::record::ReceiveIntentState::Detected {
99 outpoint,
100 ..
101 } => outpoint.clone(),
102 };
103
104 let mut tx = self
105 .kv_store
106 .begin_transaction()
107 .await
108 .map_err(Error::from)?;
109
110 let outpoint_key = outpoint_to_key(&outpoint);
112 let active = tx
113 .kv_read(
114 BDK_NAMESPACE,
115 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
116 &outpoint_key,
117 )
118 .await
119 .map_err(Error::from)?;
120
121 if active.is_some() {
122 tx.rollback().await.map_err(Error::from)?;
123 return Ok(false);
124 }
125
126 let finalized = tx
127 .kv_read(
128 BDK_NAMESPACE,
129 FINALIZED_RECEIVE_INTENT_OUTPOINT_NAMESPACE,
130 &outpoint_key,
131 )
132 .await
133 .map_err(Error::from)?;
134
135 if finalized.is_some() {
136 tx.rollback().await.map_err(Error::from)?;
137 return Ok(false);
138 }
139
140 let serialized = serde_json::to_vec(intent)?;
141 tx.kv_write(
142 BDK_NAMESPACE,
143 RECEIVE_INTENT_NAMESPACE,
144 &intent.intent_id.to_string(),
145 &serialized,
146 )
147 .await
148 .map_err(Error::from)?;
149 tx.kv_write(
150 BDK_NAMESPACE,
151 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
152 &outpoint_key,
153 intent.intent_id.to_string().as_bytes(),
154 )
155 .await
156 .map_err(Error::from)?;
157 tx.commit().await.map_err(Error::from)?;
158 Ok(true)
159 }
160
161 pub async fn get_receive_intent(
163 &self,
164 intent_id: &Uuid,
165 ) -> Result<Option<ReceiveIntentRecord>, Error> {
166 self.get_record::<ReceiveIntentRecord>(&intent_id.to_string())
167 .await
168 }
169
170 pub async fn get_all_receive_intents(&self) -> Result<Vec<ReceiveIntentRecord>, Error> {
172 self.list_records::<ReceiveIntentRecord>().await
173 }
174
175 #[cfg(test)]
177 pub async fn delete_receive_intent(&self, intent_id: &Uuid) -> Result<(), Error> {
178 let Some(intent) = self.get_receive_intent(intent_id).await? else {
179 return Ok(());
180 };
181
182 let outpoint_key = match &intent.state {
183 crate::receive::receive_intent::record::ReceiveIntentState::Detected {
184 outpoint,
185 ..
186 } => outpoint_to_key(outpoint),
187 };
188
189 let mut tx = self
190 .kv_store
191 .begin_transaction()
192 .await
193 .map_err(Error::from)?;
194 tx.kv_remove(
195 BDK_NAMESPACE,
196 RECEIVE_INTENT_NAMESPACE,
197 &intent_id.to_string(),
198 )
199 .await
200 .map_err(Error::from)?;
201 tx.kv_remove(
202 BDK_NAMESPACE,
203 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
204 &outpoint_key,
205 )
206 .await
207 .map_err(Error::from)?;
208 tx.commit().await.map_err(Error::from)?;
209 Ok(())
210 }
211
212 pub async fn finalize_receive_intent(
216 &self,
217 intent_id: &Uuid,
218 record: &FinalizedReceiveIntentRecord,
219 ) -> Result<(), Error> {
220 let Some(intent) = self.get_receive_intent(intent_id).await? else {
221 return Err(Error::ReceiveIntentNotFound(*intent_id));
222 };
223
224 let outpoint_key = match &intent.state {
225 crate::receive::receive_intent::record::ReceiveIntentState::Detected {
226 outpoint,
227 ..
228 } => outpoint_to_key(outpoint),
229 };
230
231 let serialized = serde_json::to_vec(record)?;
232 let mut tx = self
233 .kv_store
234 .begin_transaction()
235 .await
236 .map_err(Error::from)?;
237
238 tx.kv_write(
239 BDK_NAMESPACE,
240 FINALIZED_RECEIVE_INTENT_NAMESPACE,
241 &record.intent_id.to_string(),
242 &serialized,
243 )
244 .await
245 .map_err(Error::from)?;
246 tx.kv_write(
247 BDK_NAMESPACE,
248 FINALIZED_RECEIVE_INTENT_OUTPOINT_NAMESPACE,
249 &outpoint_key,
250 record.intent_id.to_string().as_bytes(),
251 )
252 .await
253 .map_err(Error::from)?;
254
255 let quote_ns = finalized_receive_intent_by_quote_namespace(&record.quote_id);
258 tx.kv_write(
259 BDK_NAMESPACE,
260 "e_ns,
261 &record.intent_id.to_string(),
262 record.intent_id.to_string().as_bytes(),
263 )
264 .await
265 .map_err(Error::from)?;
266
267 tx.kv_remove(
268 BDK_NAMESPACE,
269 RECEIVE_INTENT_NAMESPACE,
270 &intent_id.to_string(),
271 )
272 .await
273 .map_err(Error::from)?;
274 tx.kv_remove(
275 BDK_NAMESPACE,
276 RECEIVE_INTENT_OUTPOINT_NAMESPACE,
277 &outpoint_key,
278 )
279 .await
280 .map_err(Error::from)?;
281 tx.commit().await.map_err(Error::from)?;
282 Ok(())
283 }
284
285 #[cfg(test)]
287 pub async fn get_finalized_receive_intent(
288 &self,
289 intent_id: &Uuid,
290 ) -> Result<Option<FinalizedReceiveIntentRecord>, Error> {
291 self.get_record::<FinalizedReceiveIntentRecord>(&intent_id.to_string())
292 .await
293 }
294
295 pub async fn get_finalized_receive_intents_by_quote_id(
302 &self,
303 quote_id: &str,
304 ) -> Result<Vec<FinalizedReceiveIntentRecord>, Error> {
305 let quote_ns = finalized_receive_intent_by_quote_namespace(quote_id);
306 let intent_id_keys = self
307 .kv_store
308 .kv_list(BDK_NAMESPACE, "e_ns)
309 .await
310 .map_err(Error::from)?;
311
312 let mut results = Vec::new();
313 for intent_id_key in intent_id_keys {
314 if let Some(record) = self
315 .get_record::<FinalizedReceiveIntentRecord>(&intent_id_key)
316 .await?
317 {
318 results.push(record);
319 }
320 }
321 Ok(results)
322 }
323}