database.rs 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486
  1. //! FFI Database bindings
  2. use std::collections::HashMap;
  3. use std::sync::Arc;
  4. use cdk_common::database::{
  5. KVStoreDatabase as CdkKVStoreDatabase, WalletDatabase as CdkWalletDatabase,
  6. };
  7. use cdk_sql_common::pool::DatabasePool;
  8. use cdk_sql_common::SQLWalletDatabase;
  9. use crate::error::FfiError;
  10. #[cfg(feature = "postgres")]
  11. use crate::postgres::WalletPostgresDatabase;
  12. use crate::sqlite::WalletSqliteDatabase;
  13. use crate::types::*;
  14. /// FFI-compatible wallet database trait with all read and write operations
  15. /// This trait mirrors the CDK WalletDatabase trait structure
  16. #[uniffi::export(with_foreign)]
  17. #[async_trait::async_trait]
  18. pub trait WalletDatabase: Send + Sync {
  19. // ========== Read methods ==========
  20. /// Get mint from storage
  21. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError>;
  22. /// Get all mints from storage
  23. async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, FfiError>;
  24. /// Get mint keysets for mint url
  25. async fn get_mint_keysets(
  26. &self,
  27. mint_url: MintUrl,
  28. ) -> Result<Option<Vec<KeySetInfo>>, FfiError>;
  29. /// Get mint keyset by id
  30. async fn get_keyset_by_id(&self, keyset_id: Id) -> Result<Option<KeySetInfo>, FfiError>;
  31. /// Get mint quote from storage
  32. async fn get_mint_quote(&self, quote_id: String) -> Result<Option<MintQuote>, FfiError>;
  33. /// Get mint quotes from storage
  34. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError>;
  35. /// Get unissued mint quotes from storage
  36. /// Returns bolt11 quotes where nothing has been issued yet (amount_issued = 0) and all bolt12 quotes.
  37. async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError>;
  38. /// Get melt quote from storage
  39. async fn get_melt_quote(&self, quote_id: String) -> Result<Option<MeltQuote>, FfiError>;
  40. /// Get melt quotes from storage
  41. async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError>;
  42. /// Get Keys from storage
  43. async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError>;
  44. /// Get proofs from storage
  45. async fn get_proofs(
  46. &self,
  47. mint_url: Option<MintUrl>,
  48. unit: Option<CurrencyUnit>,
  49. state: Option<Vec<ProofState>>,
  50. spending_conditions: Option<Vec<SpendingConditions>>,
  51. ) -> Result<Vec<ProofInfo>, FfiError>;
  52. /// Get proofs by Y values
  53. async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, FfiError>;
  54. /// Get balance efficiently using SQL aggregation
  55. async fn get_balance(
  56. &self,
  57. mint_url: Option<MintUrl>,
  58. unit: Option<CurrencyUnit>,
  59. state: Option<Vec<ProofState>>,
  60. ) -> Result<u64, FfiError>;
  61. /// Get transaction from storage
  62. async fn get_transaction(
  63. &self,
  64. transaction_id: TransactionId,
  65. ) -> Result<Option<Transaction>, FfiError>;
  66. /// List transactions from storage
  67. async fn list_transactions(
  68. &self,
  69. mint_url: Option<MintUrl>,
  70. direction: Option<TransactionDirection>,
  71. unit: Option<CurrencyUnit>,
  72. ) -> Result<Vec<Transaction>, FfiError>;
  73. /// Read a value from the KV store
  74. async fn kv_read(
  75. &self,
  76. primary_namespace: String,
  77. secondary_namespace: String,
  78. key: String,
  79. ) -> Result<Option<Vec<u8>>, FfiError>;
  80. /// List keys in a namespace
  81. async fn kv_list(
  82. &self,
  83. primary_namespace: String,
  84. secondary_namespace: String,
  85. ) -> Result<Vec<String>, FfiError>;
  86. /// Write a value to the KV store
  87. async fn kv_write(
  88. &self,
  89. primary_namespace: String,
  90. secondary_namespace: String,
  91. key: String,
  92. value: Vec<u8>,
  93. ) -> Result<(), FfiError>;
  94. /// Remove a value from the KV store
  95. async fn kv_remove(
  96. &self,
  97. primary_namespace: String,
  98. secondary_namespace: String,
  99. key: String,
  100. ) -> Result<(), FfiError>;
  101. // ========== Write methods ==========
  102. /// Update the proofs in storage by adding new proofs or removing proofs by their Y value
  103. async fn update_proofs(
  104. &self,
  105. added: Vec<ProofInfo>,
  106. removed_ys: Vec<PublicKey>,
  107. ) -> Result<(), FfiError>;
  108. /// Update proofs state in storage
  109. async fn update_proofs_state(
  110. &self,
  111. ys: Vec<PublicKey>,
  112. state: ProofState,
  113. ) -> Result<(), FfiError>;
  114. /// Add transaction to storage
  115. async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError>;
  116. /// Remove transaction from storage
  117. async fn remove_transaction(&self, transaction_id: TransactionId) -> Result<(), FfiError>;
  118. /// Update mint url
  119. async fn update_mint_url(
  120. &self,
  121. old_mint_url: MintUrl,
  122. new_mint_url: MintUrl,
  123. ) -> Result<(), FfiError>;
  124. /// Atomically increment Keyset counter and return new value
  125. async fn increment_keyset_counter(&self, keyset_id: Id, count: u32) -> Result<u32, FfiError>;
  126. /// Add Mint to storage
  127. async fn add_mint(
  128. &self,
  129. mint_url: MintUrl,
  130. mint_info: Option<MintInfo>,
  131. ) -> Result<(), FfiError>;
  132. /// Remove Mint from storage
  133. async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError>;
  134. /// Add mint keyset to storage
  135. async fn add_mint_keysets(
  136. &self,
  137. mint_url: MintUrl,
  138. keysets: Vec<KeySetInfo>,
  139. ) -> Result<(), FfiError>;
  140. /// Add mint quote to storage
  141. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError>;
  142. /// Remove mint quote from storage
  143. async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError>;
  144. /// Add melt quote to storage
  145. async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError>;
  146. /// Remove melt quote from storage
  147. async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError>;
  148. /// Add Keys to storage
  149. async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError>;
  150. /// Remove Keys from storage
  151. async fn remove_keys(&self, id: Id) -> Result<(), FfiError>;
  152. }
  153. /// Internal bridge trait to convert from the FFI trait to the CDK database trait
  154. /// This allows us to bridge between the UniFFI trait and the CDK's internal database trait
  155. struct WalletDatabaseBridge {
  156. ffi_db: Arc<dyn WalletDatabase>,
  157. }
  158. impl WalletDatabaseBridge {
  159. fn new(ffi_db: Arc<dyn WalletDatabase>) -> Self {
  160. Self { ffi_db }
  161. }
  162. }
  163. impl std::fmt::Debug for WalletDatabaseBridge {
  164. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  165. write!(f, "WalletDatabaseBridge")
  166. }
  167. }
  168. #[async_trait::async_trait]
  169. impl cdk_common::database::KVStoreDatabase for WalletDatabaseBridge {
  170. type Err = cdk::cdk_database::Error;
  171. async fn kv_read(
  172. &self,
  173. primary_namespace: &str,
  174. secondary_namespace: &str,
  175. key: &str,
  176. ) -> Result<Option<Vec<u8>>, Self::Err> {
  177. self.ffi_db
  178. .kv_read(
  179. primary_namespace.to_string(),
  180. secondary_namespace.to_string(),
  181. key.to_string(),
  182. )
  183. .await
  184. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  185. }
  186. async fn kv_list(
  187. &self,
  188. primary_namespace: &str,
  189. secondary_namespace: &str,
  190. ) -> Result<Vec<String>, Self::Err> {
  191. self.ffi_db
  192. .kv_list(
  193. primary_namespace.to_string(),
  194. secondary_namespace.to_string(),
  195. )
  196. .await
  197. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  198. }
  199. }
  200. #[async_trait::async_trait]
  201. impl CdkWalletDatabase<cdk::cdk_database::Error> for WalletDatabaseBridge {
  202. // Mint Management
  203. async fn get_mint(
  204. &self,
  205. mint_url: cdk::mint_url::MintUrl,
  206. ) -> Result<Option<cdk::nuts::MintInfo>, cdk::cdk_database::Error> {
  207. let ffi_mint_url = mint_url.into();
  208. let result = self
  209. .ffi_db
  210. .get_mint(ffi_mint_url)
  211. .await
  212. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  213. Ok(result.map(Into::into))
  214. }
  215. async fn get_mints(
  216. &self,
  217. ) -> Result<
  218. HashMap<cdk::mint_url::MintUrl, Option<cdk::nuts::MintInfo>>,
  219. cdk::cdk_database::Error,
  220. > {
  221. let result = self
  222. .ffi_db
  223. .get_mints()
  224. .await
  225. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  226. let mut cdk_result = HashMap::new();
  227. for (ffi_mint_url, mint_info_opt) in result {
  228. let cdk_url = ffi_mint_url
  229. .try_into()
  230. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  231. cdk_result.insert(cdk_url, mint_info_opt.map(Into::into));
  232. }
  233. Ok(cdk_result)
  234. }
  235. // Keyset Management
  236. async fn get_mint_keysets(
  237. &self,
  238. mint_url: cdk::mint_url::MintUrl,
  239. ) -> Result<Option<Vec<cdk::nuts::KeySetInfo>>, cdk::cdk_database::Error> {
  240. let ffi_mint_url = mint_url.into();
  241. let result = self
  242. .ffi_db
  243. .get_mint_keysets(ffi_mint_url)
  244. .await
  245. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  246. Ok(result.map(|keysets| keysets.into_iter().map(Into::into).collect()))
  247. }
  248. async fn get_keyset_by_id(
  249. &self,
  250. keyset_id: &cdk::nuts::Id,
  251. ) -> Result<Option<cdk::nuts::KeySetInfo>, cdk::cdk_database::Error> {
  252. let ffi_id = (*keyset_id).into();
  253. let result = self
  254. .ffi_db
  255. .get_keyset_by_id(ffi_id)
  256. .await
  257. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  258. Ok(result.map(Into::into))
  259. }
  260. // Mint Quote Management
  261. async fn get_mint_quote(
  262. &self,
  263. quote_id: &str,
  264. ) -> Result<Option<cdk::wallet::MintQuote>, cdk::cdk_database::Error> {
  265. let result = self
  266. .ffi_db
  267. .get_mint_quote(quote_id.to_string())
  268. .await
  269. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  270. Ok(result
  271. .map(|q| {
  272. q.try_into()
  273. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  274. })
  275. .transpose()?)
  276. }
  277. async fn get_mint_quotes(
  278. &self,
  279. ) -> Result<Vec<cdk::wallet::MintQuote>, cdk::cdk_database::Error> {
  280. let result = self
  281. .ffi_db
  282. .get_mint_quotes()
  283. .await
  284. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  285. Ok(result
  286. .into_iter()
  287. .map(|q| {
  288. q.try_into()
  289. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  290. })
  291. .collect::<Result<Vec<_>, _>>()?)
  292. }
  293. async fn get_unissued_mint_quotes(&self) -> Result<Vec<cdk::wallet::MintQuote>, Self::Err> {
  294. let result = self
  295. .ffi_db
  296. .get_unissued_mint_quotes()
  297. .await
  298. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  299. Ok(result
  300. .into_iter()
  301. .map(|q| {
  302. q.try_into()
  303. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  304. })
  305. .collect::<Result<Vec<_>, _>>()?)
  306. }
  307. // Melt Quote Management
  308. async fn get_melt_quote(
  309. &self,
  310. quote_id: &str,
  311. ) -> Result<Option<cdk::wallet::MeltQuote>, cdk::cdk_database::Error> {
  312. let result = self
  313. .ffi_db
  314. .get_melt_quote(quote_id.to_string())
  315. .await
  316. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  317. Ok(result
  318. .map(|q| {
  319. q.try_into()
  320. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  321. })
  322. .transpose()?)
  323. }
  324. async fn get_melt_quotes(
  325. &self,
  326. ) -> Result<Vec<cdk::wallet::MeltQuote>, cdk::cdk_database::Error> {
  327. let result = self
  328. .ffi_db
  329. .get_melt_quotes()
  330. .await
  331. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  332. Ok(result
  333. .into_iter()
  334. .map(|q| {
  335. q.try_into()
  336. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  337. })
  338. .collect::<Result<Vec<_>, _>>()?)
  339. }
  340. // Keys Management
  341. async fn get_keys(
  342. &self,
  343. id: &cdk::nuts::Id,
  344. ) -> Result<Option<cdk::nuts::Keys>, cdk::cdk_database::Error> {
  345. let ffi_id: Id = (*id).into();
  346. let result = self
  347. .ffi_db
  348. .get_keys(ffi_id)
  349. .await
  350. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  351. // Convert FFI Keys back to CDK Keys using TryFrom
  352. result
  353. .map(|ffi_keys| {
  354. ffi_keys
  355. .try_into()
  356. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  357. })
  358. .transpose()
  359. }
  360. // Proof Management
  361. async fn get_proofs(
  362. &self,
  363. mint_url: Option<cdk::mint_url::MintUrl>,
  364. unit: Option<cdk::nuts::CurrencyUnit>,
  365. state: Option<Vec<cdk::nuts::State>>,
  366. spending_conditions: Option<Vec<cdk::nuts::SpendingConditions>>,
  367. ) -> Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> {
  368. let ffi_mint_url = mint_url.map(Into::into);
  369. let ffi_unit = unit.map(Into::into);
  370. let ffi_state = state.map(|s| s.into_iter().map(Into::into).collect());
  371. let ffi_spending_conditions =
  372. spending_conditions.map(|sc| sc.into_iter().map(Into::into).collect());
  373. let result = self
  374. .ffi_db
  375. .get_proofs(ffi_mint_url, ffi_unit, ffi_state, ffi_spending_conditions)
  376. .await
  377. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  378. // Convert back to CDK ProofInfo
  379. let cdk_result: Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> = result
  380. .into_iter()
  381. .map(|info| {
  382. Ok(cdk::types::ProofInfo {
  383. proof: info.proof.try_into().map_err(|e: FfiError| {
  384. cdk::cdk_database::Error::Database(e.to_string().into())
  385. })?,
  386. y: info.y.try_into().map_err(|e: FfiError| {
  387. cdk::cdk_database::Error::Database(e.to_string().into())
  388. })?,
  389. mint_url: info.mint_url.try_into().map_err(|e: FfiError| {
  390. cdk::cdk_database::Error::Database(e.to_string().into())
  391. })?,
  392. state: info.state.into(),
  393. spending_condition: info
  394. .spending_condition
  395. .map(|sc| sc.try_into())
  396. .transpose()
  397. .map_err(|e: FfiError| {
  398. cdk::cdk_database::Error::Database(e.to_string().into())
  399. })?,
  400. unit: info.unit.into(),
  401. })
  402. })
  403. .collect();
  404. cdk_result
  405. }
  406. async fn get_proofs_by_ys(
  407. &self,
  408. ys: Vec<cdk::nuts::PublicKey>,
  409. ) -> Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> {
  410. let ffi_ys: Vec<PublicKey> = ys.into_iter().map(Into::into).collect();
  411. let result = self
  412. .ffi_db
  413. .get_proofs_by_ys(ffi_ys)
  414. .await
  415. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  416. // Convert back to CDK ProofInfo
  417. let cdk_result: Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> = result
  418. .into_iter()
  419. .map(|info| {
  420. Ok(cdk::types::ProofInfo {
  421. proof: info.proof.try_into().map_err(|e: FfiError| {
  422. cdk::cdk_database::Error::Database(e.to_string().into())
  423. })?,
  424. y: info.y.try_into().map_err(|e: FfiError| {
  425. cdk::cdk_database::Error::Database(e.to_string().into())
  426. })?,
  427. mint_url: info.mint_url.try_into().map_err(|e: FfiError| {
  428. cdk::cdk_database::Error::Database(e.to_string().into())
  429. })?,
  430. state: info.state.into(),
  431. spending_condition: info
  432. .spending_condition
  433. .map(|sc| sc.try_into())
  434. .transpose()
  435. .map_err(|e: FfiError| {
  436. cdk::cdk_database::Error::Database(e.to_string().into())
  437. })?,
  438. unit: info.unit.into(),
  439. })
  440. })
  441. .collect();
  442. cdk_result
  443. }
  444. async fn get_balance(
  445. &self,
  446. mint_url: Option<cdk::mint_url::MintUrl>,
  447. unit: Option<cdk::nuts::CurrencyUnit>,
  448. state: Option<Vec<cdk::nuts::State>>,
  449. ) -> Result<u64, cdk::cdk_database::Error> {
  450. let ffi_mint_url = mint_url.map(Into::into);
  451. let ffi_unit = unit.map(Into::into);
  452. let ffi_state = state.map(|s| s.into_iter().map(Into::into).collect());
  453. self.ffi_db
  454. .get_balance(ffi_mint_url, ffi_unit, ffi_state)
  455. .await
  456. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  457. }
  458. // Transaction Management
  459. async fn get_transaction(
  460. &self,
  461. transaction_id: cdk::wallet::types::TransactionId,
  462. ) -> Result<Option<cdk::wallet::types::Transaction>, cdk::cdk_database::Error> {
  463. let ffi_id = transaction_id.into();
  464. let result = self
  465. .ffi_db
  466. .get_transaction(ffi_id)
  467. .await
  468. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  469. result
  470. .map(|tx| tx.try_into())
  471. .transpose()
  472. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  473. }
  474. async fn list_transactions(
  475. &self,
  476. mint_url: Option<cdk::mint_url::MintUrl>,
  477. direction: Option<cdk::wallet::types::TransactionDirection>,
  478. unit: Option<cdk::nuts::CurrencyUnit>,
  479. ) -> Result<Vec<cdk::wallet::types::Transaction>, cdk::cdk_database::Error> {
  480. let ffi_mint_url = mint_url.map(Into::into);
  481. let ffi_direction = direction.map(Into::into);
  482. let ffi_unit = unit.map(Into::into);
  483. let result = self
  484. .ffi_db
  485. .list_transactions(ffi_mint_url, ffi_direction, ffi_unit)
  486. .await
  487. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  488. result
  489. .into_iter()
  490. .map(|tx| tx.try_into())
  491. .collect::<Result<Vec<_>, FfiError>>()
  492. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  493. }
  494. // Write methods (non-transactional)
  495. async fn update_proofs(
  496. &self,
  497. added: Vec<cdk::types::ProofInfo>,
  498. removed_ys: Vec<cdk::nuts::PublicKey>,
  499. ) -> Result<(), cdk::cdk_database::Error> {
  500. let ffi_added: Vec<ProofInfo> = added.into_iter().map(Into::into).collect();
  501. let ffi_removed_ys: Vec<PublicKey> = removed_ys.into_iter().map(Into::into).collect();
  502. self.ffi_db
  503. .update_proofs(ffi_added, ffi_removed_ys)
  504. .await
  505. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  506. }
  507. async fn update_proofs_state(
  508. &self,
  509. ys: Vec<cdk::nuts::PublicKey>,
  510. state: cdk::nuts::State,
  511. ) -> Result<(), cdk::cdk_database::Error> {
  512. let ffi_ys: Vec<PublicKey> = ys.into_iter().map(Into::into).collect();
  513. let ffi_state = state.into();
  514. self.ffi_db
  515. .update_proofs_state(ffi_ys, ffi_state)
  516. .await
  517. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  518. }
  519. async fn add_transaction(
  520. &self,
  521. transaction: cdk::wallet::types::Transaction,
  522. ) -> Result<(), cdk::cdk_database::Error> {
  523. let ffi_transaction = transaction.into();
  524. self.ffi_db
  525. .add_transaction(ffi_transaction)
  526. .await
  527. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  528. }
  529. async fn update_mint_url(
  530. &self,
  531. old_mint_url: cdk::mint_url::MintUrl,
  532. new_mint_url: cdk::mint_url::MintUrl,
  533. ) -> Result<(), cdk::cdk_database::Error> {
  534. let ffi_old = old_mint_url.into();
  535. let ffi_new = new_mint_url.into();
  536. self.ffi_db
  537. .update_mint_url(ffi_old, ffi_new)
  538. .await
  539. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  540. }
  541. async fn increment_keyset_counter(
  542. &self,
  543. keyset_id: &cdk::nuts::Id,
  544. count: u32,
  545. ) -> Result<u32, cdk::cdk_database::Error> {
  546. let ffi_id = (*keyset_id).into();
  547. self.ffi_db
  548. .increment_keyset_counter(ffi_id, count)
  549. .await
  550. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  551. }
  552. async fn add_mint(
  553. &self,
  554. mint_url: cdk::mint_url::MintUrl,
  555. mint_info: Option<cdk::nuts::MintInfo>,
  556. ) -> Result<(), cdk::cdk_database::Error> {
  557. let ffi_mint_url = mint_url.into();
  558. let ffi_mint_info = mint_info.map(Into::into);
  559. self.ffi_db
  560. .add_mint(ffi_mint_url, ffi_mint_info)
  561. .await
  562. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  563. }
  564. async fn remove_mint(
  565. &self,
  566. mint_url: cdk::mint_url::MintUrl,
  567. ) -> Result<(), cdk::cdk_database::Error> {
  568. let ffi_mint_url = mint_url.into();
  569. self.ffi_db
  570. .remove_mint(ffi_mint_url)
  571. .await
  572. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  573. }
  574. async fn add_mint_keysets(
  575. &self,
  576. mint_url: cdk::mint_url::MintUrl,
  577. keysets: Vec<cdk::nuts::KeySetInfo>,
  578. ) -> Result<(), cdk::cdk_database::Error> {
  579. let ffi_mint_url = mint_url.into();
  580. let ffi_keysets: Vec<KeySetInfo> = keysets.into_iter().map(Into::into).collect();
  581. self.ffi_db
  582. .add_mint_keysets(ffi_mint_url, ffi_keysets)
  583. .await
  584. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  585. }
  586. async fn add_mint_quote(
  587. &self,
  588. quote: cdk::wallet::MintQuote,
  589. ) -> Result<(), cdk::cdk_database::Error> {
  590. let ffi_quote = quote.into();
  591. self.ffi_db
  592. .add_mint_quote(ffi_quote)
  593. .await
  594. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  595. }
  596. async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), cdk::cdk_database::Error> {
  597. self.ffi_db
  598. .remove_mint_quote(quote_id.to_string())
  599. .await
  600. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  601. }
  602. async fn add_melt_quote(
  603. &self,
  604. quote: cdk::wallet::MeltQuote,
  605. ) -> Result<(), cdk::cdk_database::Error> {
  606. let ffi_quote = quote.into();
  607. self.ffi_db
  608. .add_melt_quote(ffi_quote)
  609. .await
  610. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  611. }
  612. async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), cdk::cdk_database::Error> {
  613. self.ffi_db
  614. .remove_melt_quote(quote_id.to_string())
  615. .await
  616. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  617. }
  618. async fn add_keys(&self, keyset: cdk::nuts::KeySet) -> Result<(), cdk::cdk_database::Error> {
  619. let ffi_keyset: KeySet = keyset.into();
  620. self.ffi_db
  621. .add_keys(ffi_keyset)
  622. .await
  623. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  624. }
  625. async fn remove_keys(&self, id: &cdk::nuts::Id) -> Result<(), cdk::cdk_database::Error> {
  626. let ffi_id = (*id).into();
  627. self.ffi_db
  628. .remove_keys(ffi_id)
  629. .await
  630. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  631. }
  632. async fn remove_transaction(
  633. &self,
  634. transaction_id: cdk::wallet::types::TransactionId,
  635. ) -> Result<(), cdk::cdk_database::Error> {
  636. let ffi_id = transaction_id.into();
  637. self.ffi_db
  638. .remove_transaction(ffi_id)
  639. .await
  640. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  641. }
  642. // KV Store write methods
  643. async fn kv_write(
  644. &self,
  645. primary_namespace: &str,
  646. secondary_namespace: &str,
  647. key: &str,
  648. value: &[u8],
  649. ) -> Result<(), cdk::cdk_database::Error> {
  650. self.ffi_db
  651. .kv_write(
  652. primary_namespace.to_string(),
  653. secondary_namespace.to_string(),
  654. key.to_string(),
  655. value.to_vec(),
  656. )
  657. .await
  658. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  659. }
  660. async fn kv_remove(
  661. &self,
  662. primary_namespace: &str,
  663. secondary_namespace: &str,
  664. key: &str,
  665. ) -> Result<(), cdk::cdk_database::Error> {
  666. self.ffi_db
  667. .kv_remove(
  668. primary_namespace.to_string(),
  669. secondary_namespace.to_string(),
  670. key.to_string(),
  671. )
  672. .await
  673. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  674. }
  675. }
  676. pub(crate) struct FfiWalletSQLDatabase<RM>
  677. where
  678. RM: DatabasePool + 'static,
  679. {
  680. inner: SQLWalletDatabase<RM>,
  681. }
  682. impl<RM> FfiWalletSQLDatabase<RM>
  683. where
  684. RM: DatabasePool + 'static,
  685. {
  686. /// Creates a new instance
  687. pub fn new(inner: SQLWalletDatabase<RM>) -> Arc<Self> {
  688. Arc::new(Self { inner })
  689. }
  690. }
  691. // Implement WalletDatabase trait - all read and write methods
  692. #[async_trait::async_trait]
  693. impl<RM> WalletDatabase for FfiWalletSQLDatabase<RM>
  694. where
  695. RM: DatabasePool + 'static,
  696. {
  697. // ========== Read methods ==========
  698. async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, FfiError> {
  699. let cdk_ys: Vec<cdk::nuts::PublicKey> = ys
  700. .into_iter()
  701. .map(|y| y.try_into())
  702. .collect::<Result<Vec<_>, FfiError>>()?;
  703. let result = self
  704. .inner
  705. .get_proofs_by_ys(cdk_ys)
  706. .await
  707. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  708. Ok(result.into_iter().map(Into::into).collect())
  709. }
  710. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
  711. let cdk_mint_url = mint_url.try_into()?;
  712. let result = self
  713. .inner
  714. .get_mint(cdk_mint_url)
  715. .await
  716. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  717. Ok(result.map(Into::into))
  718. }
  719. async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, FfiError> {
  720. let result = self
  721. .inner
  722. .get_mints()
  723. .await
  724. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  725. Ok(result
  726. .into_iter()
  727. .map(|(k, v)| (k.into(), v.map(Into::into)))
  728. .collect())
  729. }
  730. async fn get_mint_keysets(
  731. &self,
  732. mint_url: MintUrl,
  733. ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
  734. let cdk_mint_url = mint_url.try_into()?;
  735. let result = self
  736. .inner
  737. .get_mint_keysets(cdk_mint_url)
  738. .await
  739. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  740. Ok(result.map(|keysets| keysets.into_iter().map(Into::into).collect()))
  741. }
  742. async fn get_keyset_by_id(&self, keyset_id: Id) -> Result<Option<KeySetInfo>, FfiError> {
  743. let cdk_id = keyset_id.into();
  744. let result = self
  745. .inner
  746. .get_keyset_by_id(&cdk_id)
  747. .await
  748. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  749. Ok(result.map(Into::into))
  750. }
  751. async fn get_mint_quote(&self, quote_id: String) -> Result<Option<MintQuote>, FfiError> {
  752. let result = self
  753. .inner
  754. .get_mint_quote(&quote_id)
  755. .await
  756. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  757. Ok(result.map(|q| q.into()))
  758. }
  759. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  760. let result = self
  761. .inner
  762. .get_mint_quotes()
  763. .await
  764. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  765. Ok(result.into_iter().map(|q| q.into()).collect())
  766. }
  767. async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  768. let result = self
  769. .inner
  770. .get_unissued_mint_quotes()
  771. .await
  772. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  773. Ok(result.into_iter().map(|q| q.into()).collect())
  774. }
  775. async fn get_melt_quote(&self, quote_id: String) -> Result<Option<MeltQuote>, FfiError> {
  776. let result = self
  777. .inner
  778. .get_melt_quote(&quote_id)
  779. .await
  780. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  781. Ok(result.map(|q| q.into()))
  782. }
  783. async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
  784. let result = self
  785. .inner
  786. .get_melt_quotes()
  787. .await
  788. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  789. Ok(result.into_iter().map(|q| q.into()).collect())
  790. }
  791. async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
  792. let cdk_id = id.into();
  793. let result = self
  794. .inner
  795. .get_keys(&cdk_id)
  796. .await
  797. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  798. Ok(result.map(Into::into))
  799. }
  800. async fn get_proofs(
  801. &self,
  802. mint_url: Option<MintUrl>,
  803. unit: Option<CurrencyUnit>,
  804. state: Option<Vec<ProofState>>,
  805. spending_conditions: Option<Vec<SpendingConditions>>,
  806. ) -> Result<Vec<ProofInfo>, FfiError> {
  807. let cdk_mint_url = mint_url.map(|u| u.try_into()).transpose()?;
  808. let cdk_unit = unit.map(Into::into);
  809. let cdk_state = state.map(|s| s.into_iter().map(Into::into).collect());
  810. let cdk_spending_conditions: Option<Vec<cdk::nuts::SpendingConditions>> =
  811. spending_conditions
  812. .map(|sc| {
  813. sc.into_iter()
  814. .map(|c| c.try_into())
  815. .collect::<Result<Vec<_>, FfiError>>()
  816. })
  817. .transpose()?;
  818. let result = self
  819. .inner
  820. .get_proofs(cdk_mint_url, cdk_unit, cdk_state, cdk_spending_conditions)
  821. .await
  822. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  823. Ok(result.into_iter().map(Into::into).collect())
  824. }
  825. async fn get_balance(
  826. &self,
  827. mint_url: Option<MintUrl>,
  828. unit: Option<CurrencyUnit>,
  829. state: Option<Vec<ProofState>>,
  830. ) -> Result<u64, FfiError> {
  831. let cdk_mint_url = mint_url.map(|u| u.try_into()).transpose()?;
  832. let cdk_unit = unit.map(Into::into);
  833. let cdk_state = state.map(|s| s.into_iter().map(Into::into).collect());
  834. self.inner
  835. .get_balance(cdk_mint_url, cdk_unit, cdk_state)
  836. .await
  837. .map_err(|e| FfiError::Database { msg: e.to_string() })
  838. }
  839. async fn get_transaction(
  840. &self,
  841. transaction_id: TransactionId,
  842. ) -> Result<Option<Transaction>, FfiError> {
  843. let cdk_id = transaction_id.try_into()?;
  844. let result = self
  845. .inner
  846. .get_transaction(cdk_id)
  847. .await
  848. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  849. Ok(result.map(Into::into))
  850. }
  851. async fn list_transactions(
  852. &self,
  853. mint_url: Option<MintUrl>,
  854. direction: Option<TransactionDirection>,
  855. unit: Option<CurrencyUnit>,
  856. ) -> Result<Vec<Transaction>, FfiError> {
  857. let cdk_mint_url = mint_url.map(|u| u.try_into()).transpose()?;
  858. let cdk_direction = direction.map(Into::into);
  859. let cdk_unit = unit.map(Into::into);
  860. let result = self
  861. .inner
  862. .list_transactions(cdk_mint_url, cdk_direction, cdk_unit)
  863. .await
  864. .map_err(|e| FfiError::Database { msg: e.to_string() })?;
  865. Ok(result.into_iter().map(Into::into).collect())
  866. }
  867. async fn kv_read(
  868. &self,
  869. primary_namespace: String,
  870. secondary_namespace: String,
  871. key: String,
  872. ) -> Result<Option<Vec<u8>>, FfiError> {
  873. self.inner
  874. .kv_read(&primary_namespace, &secondary_namespace, &key)
  875. .await
  876. .map_err(|e| FfiError::Database { msg: e.to_string() })
  877. }
  878. async fn kv_list(
  879. &self,
  880. primary_namespace: String,
  881. secondary_namespace: String,
  882. ) -> Result<Vec<String>, FfiError> {
  883. self.inner
  884. .kv_list(&primary_namespace, &secondary_namespace)
  885. .await
  886. .map_err(|e| FfiError::Database { msg: e.to_string() })
  887. }
  888. async fn kv_write(
  889. &self,
  890. primary_namespace: String,
  891. secondary_namespace: String,
  892. key: String,
  893. value: Vec<u8>,
  894. ) -> Result<(), FfiError> {
  895. self.inner
  896. .kv_write(&primary_namespace, &secondary_namespace, &key, &value)
  897. .await
  898. .map_err(|e| FfiError::Database { msg: e.to_string() })
  899. }
  900. async fn kv_remove(
  901. &self,
  902. primary_namespace: String,
  903. secondary_namespace: String,
  904. key: String,
  905. ) -> Result<(), FfiError> {
  906. self.inner
  907. .kv_remove(&primary_namespace, &secondary_namespace, &key)
  908. .await
  909. .map_err(|e| FfiError::Database { msg: e.to_string() })
  910. }
  911. // ========== Write methods ==========
  912. async fn update_proofs(
  913. &self,
  914. added: Vec<ProofInfo>,
  915. removed_ys: Vec<PublicKey>,
  916. ) -> Result<(), FfiError> {
  917. let cdk_added: Result<Vec<cdk::types::ProofInfo>, FfiError> = added
  918. .into_iter()
  919. .map(|info| {
  920. Ok::<cdk::types::ProofInfo, FfiError>(cdk::types::ProofInfo {
  921. proof: info.proof.try_into()?,
  922. y: info.y.try_into()?,
  923. mint_url: info.mint_url.try_into()?,
  924. state: info.state.into(),
  925. spending_condition: info
  926. .spending_condition
  927. .map(|sc| sc.try_into())
  928. .transpose()?,
  929. unit: info.unit.into(),
  930. })
  931. })
  932. .collect();
  933. let cdk_added = cdk_added?;
  934. let cdk_removed_ys: Result<Vec<cdk::nuts::PublicKey>, FfiError> =
  935. removed_ys.into_iter().map(|pk| pk.try_into()).collect();
  936. let cdk_removed_ys = cdk_removed_ys?;
  937. self.inner
  938. .update_proofs(cdk_added, cdk_removed_ys)
  939. .await
  940. .map_err(|e| FfiError::Database { msg: e.to_string() })
  941. }
  942. async fn update_proofs_state(
  943. &self,
  944. ys: Vec<PublicKey>,
  945. state: ProofState,
  946. ) -> Result<(), FfiError> {
  947. let cdk_ys: Result<Vec<cdk::nuts::PublicKey>, FfiError> =
  948. ys.into_iter().map(|pk| pk.try_into()).collect();
  949. let cdk_ys = cdk_ys?;
  950. let cdk_state = state.into();
  951. self.inner
  952. .update_proofs_state(cdk_ys, cdk_state)
  953. .await
  954. .map_err(|e| FfiError::Database { msg: e.to_string() })
  955. }
  956. async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
  957. let cdk_transaction: cdk::wallet::types::Transaction = transaction.try_into()?;
  958. self.inner
  959. .add_transaction(cdk_transaction)
  960. .await
  961. .map_err(|e| FfiError::Database { msg: e.to_string() })
  962. }
  963. async fn remove_transaction(&self, transaction_id: TransactionId) -> Result<(), FfiError> {
  964. let cdk_id = transaction_id.try_into()?;
  965. self.inner
  966. .remove_transaction(cdk_id)
  967. .await
  968. .map_err(|e| FfiError::Database { msg: e.to_string() })
  969. }
  970. async fn update_mint_url(
  971. &self,
  972. old_mint_url: MintUrl,
  973. new_mint_url: MintUrl,
  974. ) -> Result<(), FfiError> {
  975. let cdk_old = old_mint_url.try_into()?;
  976. let cdk_new = new_mint_url.try_into()?;
  977. self.inner
  978. .update_mint_url(cdk_old, cdk_new)
  979. .await
  980. .map_err(|e| FfiError::Database { msg: e.to_string() })
  981. }
  982. async fn increment_keyset_counter(&self, keyset_id: Id, count: u32) -> Result<u32, FfiError> {
  983. let cdk_id = keyset_id.into();
  984. self.inner
  985. .increment_keyset_counter(&cdk_id, count)
  986. .await
  987. .map_err(|e| FfiError::Database { msg: e.to_string() })
  988. }
  989. async fn add_mint(
  990. &self,
  991. mint_url: MintUrl,
  992. mint_info: Option<MintInfo>,
  993. ) -> Result<(), FfiError> {
  994. let cdk_mint_url = mint_url.try_into()?;
  995. let cdk_mint_info = mint_info.map(Into::into);
  996. self.inner
  997. .add_mint(cdk_mint_url, cdk_mint_info)
  998. .await
  999. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1000. }
  1001. async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
  1002. let cdk_mint_url = mint_url.try_into()?;
  1003. self.inner
  1004. .remove_mint(cdk_mint_url)
  1005. .await
  1006. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1007. }
  1008. async fn add_mint_keysets(
  1009. &self,
  1010. mint_url: MintUrl,
  1011. keysets: Vec<KeySetInfo>,
  1012. ) -> Result<(), FfiError> {
  1013. let cdk_mint_url = mint_url.try_into()?;
  1014. let cdk_keysets: Vec<cdk::nuts::KeySetInfo> = keysets.into_iter().map(Into::into).collect();
  1015. self.inner
  1016. .add_mint_keysets(cdk_mint_url, cdk_keysets)
  1017. .await
  1018. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1019. }
  1020. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
  1021. let cdk_quote = quote.try_into()?;
  1022. self.inner
  1023. .add_mint_quote(cdk_quote)
  1024. .await
  1025. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1026. }
  1027. async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1028. self.inner
  1029. .remove_mint_quote(&quote_id)
  1030. .await
  1031. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1032. }
  1033. async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
  1034. let cdk_quote = quote.try_into()?;
  1035. self.inner
  1036. .add_melt_quote(cdk_quote)
  1037. .await
  1038. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1039. }
  1040. async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1041. self.inner
  1042. .remove_melt_quote(&quote_id)
  1043. .await
  1044. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1045. }
  1046. async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
  1047. let cdk_keyset: cdk::nuts::KeySet = keyset.try_into()?;
  1048. self.inner
  1049. .add_keys(cdk_keyset)
  1050. .await
  1051. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1052. }
  1053. async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
  1054. let cdk_id = id.into();
  1055. self.inner
  1056. .remove_keys(&cdk_id)
  1057. .await
  1058. .map_err(|e| FfiError::Database { msg: e.to_string() })
  1059. }
  1060. }
  1061. /// Macro to implement WalletDatabase for wrapper types that delegate to an inner FfiWalletSQLDatabase.
  1062. /// This eliminates duplication between SQLite and Postgres FFI implementations.
  1063. ///
  1064. /// Requirements: The following types must be in scope where this macro is invoked:
  1065. /// - WalletDatabase, FfiError, PublicKey, ProofInfo, MintUrl, MintInfo, KeySetInfo, Id,
  1066. /// MintQuote, MeltQuote, Keys, CurrencyUnit, ProofState, SpendingConditions, Transaction,
  1067. /// TransactionId, TransactionDirection, KeySet
  1068. /// - std::collections::HashMap
  1069. #[macro_export]
  1070. macro_rules! impl_ffi_wallet_database {
  1071. ($wrapper_type:ty) => {
  1072. #[uniffi::export(async_runtime = "tokio")]
  1073. #[async_trait::async_trait]
  1074. impl WalletDatabase for $wrapper_type {
  1075. // ========== Read methods ==========
  1076. async fn get_proofs_by_ys(
  1077. &self,
  1078. ys: Vec<PublicKey>,
  1079. ) -> Result<Vec<ProofInfo>, FfiError> {
  1080. self.inner.get_proofs_by_ys(ys).await
  1081. }
  1082. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
  1083. self.inner.get_mint(mint_url).await
  1084. }
  1085. async fn get_mints(
  1086. &self,
  1087. ) -> Result<std::collections::HashMap<MintUrl, Option<MintInfo>>, FfiError> {
  1088. self.inner.get_mints().await
  1089. }
  1090. async fn get_mint_keysets(
  1091. &self,
  1092. mint_url: MintUrl,
  1093. ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
  1094. self.inner.get_mint_keysets(mint_url).await
  1095. }
  1096. async fn get_keyset_by_id(
  1097. &self,
  1098. keyset_id: Id,
  1099. ) -> Result<Option<KeySetInfo>, FfiError> {
  1100. self.inner.get_keyset_by_id(keyset_id).await
  1101. }
  1102. async fn get_mint_quote(
  1103. &self,
  1104. quote_id: String,
  1105. ) -> Result<Option<MintQuote>, FfiError> {
  1106. self.inner.get_mint_quote(quote_id).await
  1107. }
  1108. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  1109. self.inner.get_mint_quotes().await
  1110. }
  1111. async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  1112. self.inner.get_unissued_mint_quotes().await
  1113. }
  1114. async fn get_melt_quote(
  1115. &self,
  1116. quote_id: String,
  1117. ) -> Result<Option<MeltQuote>, FfiError> {
  1118. self.inner.get_melt_quote(quote_id).await
  1119. }
  1120. async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
  1121. self.inner.get_melt_quotes().await
  1122. }
  1123. async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
  1124. self.inner.get_keys(id).await
  1125. }
  1126. async fn get_proofs(
  1127. &self,
  1128. mint_url: Option<MintUrl>,
  1129. unit: Option<CurrencyUnit>,
  1130. state: Option<Vec<ProofState>>,
  1131. spending_conditions: Option<Vec<SpendingConditions>>,
  1132. ) -> Result<Vec<ProofInfo>, FfiError> {
  1133. self.inner
  1134. .get_proofs(mint_url, unit, state, spending_conditions)
  1135. .await
  1136. }
  1137. async fn get_balance(
  1138. &self,
  1139. mint_url: Option<MintUrl>,
  1140. unit: Option<CurrencyUnit>,
  1141. state: Option<Vec<ProofState>>,
  1142. ) -> Result<u64, FfiError> {
  1143. self.inner.get_balance(mint_url, unit, state).await
  1144. }
  1145. async fn get_transaction(
  1146. &self,
  1147. transaction_id: TransactionId,
  1148. ) -> Result<Option<Transaction>, FfiError> {
  1149. self.inner.get_transaction(transaction_id).await
  1150. }
  1151. async fn list_transactions(
  1152. &self,
  1153. mint_url: Option<MintUrl>,
  1154. direction: Option<TransactionDirection>,
  1155. unit: Option<CurrencyUnit>,
  1156. ) -> Result<Vec<Transaction>, FfiError> {
  1157. self.inner
  1158. .list_transactions(mint_url, direction, unit)
  1159. .await
  1160. }
  1161. async fn kv_read(
  1162. &self,
  1163. primary_namespace: String,
  1164. secondary_namespace: String,
  1165. key: String,
  1166. ) -> Result<Option<Vec<u8>>, FfiError> {
  1167. self.inner
  1168. .kv_read(primary_namespace, secondary_namespace, key)
  1169. .await
  1170. }
  1171. async fn kv_list(
  1172. &self,
  1173. primary_namespace: String,
  1174. secondary_namespace: String,
  1175. ) -> Result<Vec<String>, FfiError> {
  1176. self.inner
  1177. .kv_list(primary_namespace, secondary_namespace)
  1178. .await
  1179. }
  1180. async fn kv_write(
  1181. &self,
  1182. primary_namespace: String,
  1183. secondary_namespace: String,
  1184. key: String,
  1185. value: Vec<u8>,
  1186. ) -> Result<(), FfiError> {
  1187. self.inner
  1188. .kv_write(primary_namespace, secondary_namespace, key, value)
  1189. .await
  1190. }
  1191. async fn kv_remove(
  1192. &self,
  1193. primary_namespace: String,
  1194. secondary_namespace: String,
  1195. key: String,
  1196. ) -> Result<(), FfiError> {
  1197. self.inner
  1198. .kv_remove(primary_namespace, secondary_namespace, key)
  1199. .await
  1200. }
  1201. // ========== Write methods ==========
  1202. async fn update_proofs(
  1203. &self,
  1204. added: Vec<ProofInfo>,
  1205. removed_ys: Vec<PublicKey>,
  1206. ) -> Result<(), FfiError> {
  1207. self.inner.update_proofs(added, removed_ys).await
  1208. }
  1209. async fn update_proofs_state(
  1210. &self,
  1211. ys: Vec<PublicKey>,
  1212. state: ProofState,
  1213. ) -> Result<(), FfiError> {
  1214. self.inner.update_proofs_state(ys, state).await
  1215. }
  1216. async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
  1217. self.inner.add_transaction(transaction).await
  1218. }
  1219. async fn remove_transaction(
  1220. &self,
  1221. transaction_id: TransactionId,
  1222. ) -> Result<(), FfiError> {
  1223. self.inner.remove_transaction(transaction_id).await
  1224. }
  1225. async fn update_mint_url(
  1226. &self,
  1227. old_mint_url: MintUrl,
  1228. new_mint_url: MintUrl,
  1229. ) -> Result<(), FfiError> {
  1230. self.inner.update_mint_url(old_mint_url, new_mint_url).await
  1231. }
  1232. async fn increment_keyset_counter(
  1233. &self,
  1234. keyset_id: Id,
  1235. count: u32,
  1236. ) -> Result<u32, FfiError> {
  1237. self.inner.increment_keyset_counter(keyset_id, count).await
  1238. }
  1239. async fn add_mint(
  1240. &self,
  1241. mint_url: MintUrl,
  1242. mint_info: Option<MintInfo>,
  1243. ) -> Result<(), FfiError> {
  1244. self.inner.add_mint(mint_url, mint_info).await
  1245. }
  1246. async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
  1247. self.inner.remove_mint(mint_url).await
  1248. }
  1249. async fn add_mint_keysets(
  1250. &self,
  1251. mint_url: MintUrl,
  1252. keysets: Vec<KeySetInfo>,
  1253. ) -> Result<(), FfiError> {
  1254. self.inner.add_mint_keysets(mint_url, keysets).await
  1255. }
  1256. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
  1257. self.inner.add_mint_quote(quote).await
  1258. }
  1259. async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1260. self.inner.remove_mint_quote(quote_id).await
  1261. }
  1262. async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
  1263. self.inner.add_melt_quote(quote).await
  1264. }
  1265. async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1266. self.inner.remove_melt_quote(quote_id).await
  1267. }
  1268. async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
  1269. self.inner.add_keys(keyset).await
  1270. }
  1271. async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
  1272. self.inner.remove_keys(id).await
  1273. }
  1274. }
  1275. };
  1276. }
  1277. /// FFI-safe database type enum
  1278. #[derive(uniffi::Enum, Clone)]
  1279. pub enum WalletDbBackend {
  1280. Sqlite {
  1281. path: String,
  1282. },
  1283. #[cfg(feature = "postgres")]
  1284. Postgres {
  1285. url: String,
  1286. },
  1287. }
  1288. /// Factory helpers returning a CDK wallet database behind the FFI trait
  1289. #[uniffi::export]
  1290. pub fn create_wallet_db(backend: WalletDbBackend) -> Result<Arc<dyn WalletDatabase>, FfiError> {
  1291. match backend {
  1292. WalletDbBackend::Sqlite { path } => {
  1293. let sqlite = WalletSqliteDatabase::new(path)?;
  1294. Ok(sqlite as Arc<dyn WalletDatabase>)
  1295. }
  1296. #[cfg(feature = "postgres")]
  1297. WalletDbBackend::Postgres { url } => {
  1298. let pg = WalletPostgresDatabase::new(url)?;
  1299. Ok(pg as Arc<dyn WalletDatabase>)
  1300. }
  1301. }
  1302. }
  1303. /// Helper function to create a CDK database from the FFI trait
  1304. pub fn create_cdk_database_from_ffi(
  1305. ffi_db: Arc<dyn WalletDatabase>,
  1306. ) -> Arc<dyn CdkWalletDatabase<cdk::cdk_database::Error> + Send + Sync> {
  1307. Arc::new(WalletDatabaseBridge::new(ffi_db))
  1308. }