database.rs 48 KB

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