database.rs 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932
  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_common::wallet::WalletSaga;
  6. use cdk_sql_common::pool::DatabasePool;
  7. use cdk_sql_common::SQLWalletDatabase;
  8. use crate::error::FfiError;
  9. #[cfg(feature = "postgres")]
  10. use crate::postgres::WalletPostgresDatabase;
  11. use crate::sqlite::WalletSqliteDatabase;
  12. use crate::types::*;
  13. /// FFI-compatible wallet database trait with all read and write operations
  14. /// This trait mirrors the CDK WalletDatabase trait structure
  15. #[uniffi::export(with_foreign)]
  16. #[async_trait::async_trait]
  17. pub trait WalletDatabase: Send + Sync {
  18. // ========== Read methods ==========
  19. /// Get mint from storage
  20. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError>;
  21. /// Get all mints from storage
  22. async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, FfiError>;
  23. /// Get mint keysets for mint url
  24. async fn get_mint_keysets(
  25. &self,
  26. mint_url: MintUrl,
  27. ) -> Result<Option<Vec<KeySetInfo>>, FfiError>;
  28. /// Get mint keyset by id
  29. async fn get_keyset_by_id(&self, keyset_id: Id) -> Result<Option<KeySetInfo>, FfiError>;
  30. /// Get mint quote from storage
  31. async fn get_mint_quote(&self, quote_id: String) -> Result<Option<MintQuote>, FfiError>;
  32. /// Get mint quotes from storage
  33. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError>;
  34. /// Get unissued mint quotes from storage
  35. /// Returns bolt11 quotes where nothing has been issued yet (amount_issued = 0) and all bolt12 quotes.
  36. async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError>;
  37. /// Get melt quote from storage
  38. async fn get_melt_quote(&self, quote_id: String) -> Result<Option<MeltQuote>, FfiError>;
  39. /// Get melt quotes from storage
  40. async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError>;
  41. /// Get Keys from storage
  42. async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError>;
  43. /// Get proofs from storage
  44. async fn get_proofs(
  45. &self,
  46. mint_url: Option<MintUrl>,
  47. unit: Option<CurrencyUnit>,
  48. state: Option<Vec<ProofState>>,
  49. spending_conditions: Option<Vec<SpendingConditions>>,
  50. ) -> Result<Vec<ProofInfo>, FfiError>;
  51. /// Get proofs by Y values
  52. async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, FfiError>;
  53. /// Get balance efficiently using SQL aggregation
  54. async fn get_balance(
  55. &self,
  56. mint_url: Option<MintUrl>,
  57. unit: Option<CurrencyUnit>,
  58. state: Option<Vec<ProofState>>,
  59. ) -> Result<u64, FfiError>;
  60. /// Get transaction from storage
  61. async fn get_transaction(
  62. &self,
  63. transaction_id: TransactionId,
  64. ) -> Result<Option<Transaction>, FfiError>;
  65. /// List transactions from storage
  66. async fn list_transactions(
  67. &self,
  68. mint_url: Option<MintUrl>,
  69. direction: Option<TransactionDirection>,
  70. unit: Option<CurrencyUnit>,
  71. ) -> Result<Vec<Transaction>, FfiError>;
  72. /// Read a value from the KV store
  73. async fn kv_read(
  74. &self,
  75. primary_namespace: String,
  76. secondary_namespace: String,
  77. key: String,
  78. ) -> Result<Option<Vec<u8>>, FfiError>;
  79. /// List keys in a namespace
  80. async fn kv_list(
  81. &self,
  82. primary_namespace: String,
  83. secondary_namespace: String,
  84. ) -> Result<Vec<String>, FfiError>;
  85. /// Write a value to the KV store
  86. async fn kv_write(
  87. &self,
  88. primary_namespace: String,
  89. secondary_namespace: String,
  90. key: String,
  91. value: Vec<u8>,
  92. ) -> Result<(), FfiError>;
  93. /// Remove a value from the KV store
  94. async fn kv_remove(
  95. &self,
  96. primary_namespace: String,
  97. secondary_namespace: String,
  98. key: String,
  99. ) -> Result<(), FfiError>;
  100. // ========== Write methods ==========
  101. /// Update the proofs in storage by adding new proofs or removing proofs by their Y value
  102. async fn update_proofs(
  103. &self,
  104. added: Vec<ProofInfo>,
  105. removed_ys: Vec<PublicKey>,
  106. ) -> Result<(), FfiError>;
  107. /// Update proofs state in storage
  108. async fn update_proofs_state(
  109. &self,
  110. ys: Vec<PublicKey>,
  111. state: ProofState,
  112. ) -> Result<(), FfiError>;
  113. /// Add transaction to storage
  114. async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError>;
  115. /// Remove transaction from storage
  116. async fn remove_transaction(&self, transaction_id: TransactionId) -> Result<(), FfiError>;
  117. /// Update mint url
  118. async fn update_mint_url(
  119. &self,
  120. old_mint_url: MintUrl,
  121. new_mint_url: MintUrl,
  122. ) -> Result<(), FfiError>;
  123. /// Atomically increment Keyset counter and return new value
  124. async fn increment_keyset_counter(&self, keyset_id: Id, count: u32) -> Result<u32, FfiError>;
  125. /// Add Mint to storage
  126. async fn add_mint(
  127. &self,
  128. mint_url: MintUrl,
  129. mint_info: Option<MintInfo>,
  130. ) -> Result<(), FfiError>;
  131. /// Remove Mint from storage
  132. async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError>;
  133. /// Add mint keyset to storage
  134. async fn add_mint_keysets(
  135. &self,
  136. mint_url: MintUrl,
  137. keysets: Vec<KeySetInfo>,
  138. ) -> Result<(), FfiError>;
  139. /// Add mint quote to storage
  140. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError>;
  141. /// Remove mint quote from storage
  142. async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError>;
  143. /// Add melt quote to storage
  144. async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError>;
  145. /// Remove melt quote from storage
  146. async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError>;
  147. /// Add Keys to storage
  148. async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError>;
  149. /// Remove Keys from storage
  150. async fn remove_keys(&self, id: Id) -> Result<(), FfiError>;
  151. // ========== Saga management methods ==========
  152. // WalletSaga is serialized as JSON for FFI compatibility
  153. /// Add a wallet saga to storage (JSON serialized)
  154. async fn add_saga(&self, saga_json: String) -> Result<(), FfiError>;
  155. /// Get a wallet saga by ID (returns JSON serialized)
  156. async fn get_saga(&self, id: String) -> Result<Option<String>, FfiError>;
  157. /// Update a wallet saga (JSON serialized) with optimistic locking.
  158. ///
  159. /// Returns `true` if the update succeeded (version matched),
  160. /// `false` if another instance modified the saga first.
  161. async fn update_saga(&self, saga_json: String) -> Result<bool, FfiError>;
  162. /// Delete a wallet saga
  163. async fn delete_saga(&self, id: String) -> Result<(), FfiError>;
  164. /// Get all incomplete sagas (returns JSON serialized sagas)
  165. async fn get_incomplete_sagas(&self) -> Result<Vec<String>, FfiError>;
  166. // ========== Proof reservation methods ==========
  167. /// Reserve proofs for an operation
  168. async fn reserve_proofs(
  169. &self,
  170. ys: Vec<PublicKey>,
  171. operation_id: String,
  172. ) -> Result<(), FfiError>;
  173. /// Release proofs reserved by an operation
  174. async fn release_proofs(&self, operation_id: String) -> Result<(), FfiError>;
  175. /// Get proofs reserved by an operation
  176. async fn get_reserved_proofs(&self, operation_id: String) -> Result<Vec<ProofInfo>, FfiError>;
  177. // ========== Quote reservation methods ==========
  178. /// Reserve a melt quote for an operation
  179. async fn reserve_melt_quote(
  180. &self,
  181. quote_id: String,
  182. operation_id: String,
  183. ) -> Result<(), FfiError>;
  184. /// Release a melt quote reserved by an operation
  185. async fn release_melt_quote(&self, operation_id: String) -> Result<(), FfiError>;
  186. /// Reserve a mint quote for an operation
  187. async fn reserve_mint_quote(
  188. &self,
  189. quote_id: String,
  190. operation_id: String,
  191. ) -> Result<(), FfiError>;
  192. /// Release a mint quote reserved by an operation
  193. async fn release_mint_quote(&self, operation_id: String) -> Result<(), FfiError>;
  194. }
  195. /// Internal bridge trait to convert from the FFI trait to the CDK database trait
  196. /// This allows us to bridge between the UniFFI trait and the CDK's internal database trait
  197. struct WalletDatabaseBridge {
  198. ffi_db: Arc<dyn WalletDatabase>,
  199. }
  200. impl WalletDatabaseBridge {
  201. fn new(ffi_db: Arc<dyn WalletDatabase>) -> Self {
  202. Self { ffi_db }
  203. }
  204. }
  205. impl std::fmt::Debug for WalletDatabaseBridge {
  206. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  207. write!(f, "WalletDatabaseBridge")
  208. }
  209. }
  210. #[async_trait::async_trait]
  211. impl CdkWalletDatabase<cdk::cdk_database::Error> for WalletDatabaseBridge {
  212. async fn kv_read(
  213. &self,
  214. primary_namespace: &str,
  215. secondary_namespace: &str,
  216. key: &str,
  217. ) -> Result<Option<Vec<u8>>, cdk::cdk_database::Error> {
  218. self.ffi_db
  219. .kv_read(
  220. primary_namespace.to_string(),
  221. secondary_namespace.to_string(),
  222. key.to_string(),
  223. )
  224. .await
  225. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  226. }
  227. async fn kv_list(
  228. &self,
  229. primary_namespace: &str,
  230. secondary_namespace: &str,
  231. ) -> Result<Vec<String>, cdk::cdk_database::Error> {
  232. self.ffi_db
  233. .kv_list(
  234. primary_namespace.to_string(),
  235. secondary_namespace.to_string(),
  236. )
  237. .await
  238. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  239. }
  240. // Mint Management
  241. async fn get_mint(
  242. &self,
  243. mint_url: cdk::mint_url::MintUrl,
  244. ) -> Result<Option<cdk::nuts::MintInfo>, cdk::cdk_database::Error> {
  245. let ffi_mint_url = mint_url.into();
  246. let result = self
  247. .ffi_db
  248. .get_mint(ffi_mint_url)
  249. .await
  250. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  251. Ok(result.map(Into::into))
  252. }
  253. async fn get_mints(
  254. &self,
  255. ) -> Result<
  256. HashMap<cdk::mint_url::MintUrl, Option<cdk::nuts::MintInfo>>,
  257. cdk::cdk_database::Error,
  258. > {
  259. let result = self
  260. .ffi_db
  261. .get_mints()
  262. .await
  263. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  264. let mut cdk_result = HashMap::new();
  265. for (ffi_mint_url, mint_info_opt) in result {
  266. let cdk_url = ffi_mint_url
  267. .try_into()
  268. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  269. cdk_result.insert(cdk_url, mint_info_opt.map(Into::into));
  270. }
  271. Ok(cdk_result)
  272. }
  273. // Keyset Management
  274. async fn get_mint_keysets(
  275. &self,
  276. mint_url: cdk::mint_url::MintUrl,
  277. ) -> Result<Option<Vec<cdk::nuts::KeySetInfo>>, cdk::cdk_database::Error> {
  278. let ffi_mint_url = mint_url.into();
  279. let result = self
  280. .ffi_db
  281. .get_mint_keysets(ffi_mint_url)
  282. .await
  283. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  284. Ok(result.map(|keysets| keysets.into_iter().map(Into::into).collect()))
  285. }
  286. async fn get_keyset_by_id(
  287. &self,
  288. keyset_id: &cdk::nuts::Id,
  289. ) -> Result<Option<cdk::nuts::KeySetInfo>, cdk::cdk_database::Error> {
  290. let ffi_id = (*keyset_id).into();
  291. let result = self
  292. .ffi_db
  293. .get_keyset_by_id(ffi_id)
  294. .await
  295. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  296. Ok(result.map(Into::into))
  297. }
  298. // Mint Quote Management
  299. async fn get_mint_quote(
  300. &self,
  301. quote_id: &str,
  302. ) -> Result<Option<cdk::wallet::MintQuote>, cdk::cdk_database::Error> {
  303. let result = self
  304. .ffi_db
  305. .get_mint_quote(quote_id.to_string())
  306. .await
  307. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  308. Ok(result
  309. .map(|q| {
  310. q.try_into()
  311. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  312. })
  313. .transpose()?)
  314. }
  315. async fn get_mint_quotes(
  316. &self,
  317. ) -> Result<Vec<cdk::wallet::MintQuote>, cdk::cdk_database::Error> {
  318. let result = self
  319. .ffi_db
  320. .get_mint_quotes()
  321. .await
  322. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  323. Ok(result
  324. .into_iter()
  325. .map(|q| {
  326. q.try_into()
  327. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  328. })
  329. .collect::<Result<Vec<_>, _>>()?)
  330. }
  331. async fn get_unissued_mint_quotes(
  332. &self,
  333. ) -> Result<Vec<cdk::wallet::MintQuote>, cdk::cdk_database::Error> {
  334. let result = self
  335. .ffi_db
  336. .get_unissued_mint_quotes()
  337. .await
  338. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  339. Ok(result
  340. .into_iter()
  341. .map(|q| {
  342. q.try_into()
  343. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  344. })
  345. .collect::<Result<Vec<_>, _>>()?)
  346. }
  347. // Melt Quote Management
  348. async fn get_melt_quote(
  349. &self,
  350. quote_id: &str,
  351. ) -> Result<Option<cdk::wallet::MeltQuote>, cdk::cdk_database::Error> {
  352. let result = self
  353. .ffi_db
  354. .get_melt_quote(quote_id.to_string())
  355. .await
  356. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  357. Ok(result
  358. .map(|q| {
  359. q.try_into()
  360. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  361. })
  362. .transpose()?)
  363. }
  364. async fn get_melt_quotes(
  365. &self,
  366. ) -> Result<Vec<cdk::wallet::MeltQuote>, cdk::cdk_database::Error> {
  367. let result = self
  368. .ffi_db
  369. .get_melt_quotes()
  370. .await
  371. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  372. Ok(result
  373. .into_iter()
  374. .map(|q| {
  375. q.try_into()
  376. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  377. })
  378. .collect::<Result<Vec<_>, _>>()?)
  379. }
  380. // Keys Management
  381. async fn get_keys(
  382. &self,
  383. id: &cdk::nuts::Id,
  384. ) -> Result<Option<cdk::nuts::Keys>, cdk::cdk_database::Error> {
  385. let ffi_id: Id = (*id).into();
  386. let result = self
  387. .ffi_db
  388. .get_keys(ffi_id)
  389. .await
  390. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  391. // Convert FFI Keys back to CDK Keys using TryFrom
  392. result
  393. .map(|ffi_keys| {
  394. ffi_keys
  395. .try_into()
  396. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  397. })
  398. .transpose()
  399. }
  400. // Proof Management
  401. async fn get_proofs(
  402. &self,
  403. mint_url: Option<cdk::mint_url::MintUrl>,
  404. unit: Option<cdk::nuts::CurrencyUnit>,
  405. state: Option<Vec<cdk::nuts::State>>,
  406. spending_conditions: Option<Vec<cdk::nuts::SpendingConditions>>,
  407. ) -> Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> {
  408. let ffi_mint_url = mint_url.map(Into::into);
  409. let ffi_unit = unit.map(Into::into);
  410. let ffi_state = state.map(|s| s.into_iter().map(Into::into).collect());
  411. let ffi_spending_conditions =
  412. spending_conditions.map(|sc| sc.into_iter().map(Into::into).collect());
  413. let result = self
  414. .ffi_db
  415. .get_proofs(ffi_mint_url, ffi_unit, ffi_state, ffi_spending_conditions)
  416. .await
  417. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  418. // Convert back to CDK ProofInfo
  419. let cdk_result: Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> = result
  420. .into_iter()
  421. .map(|info| {
  422. Ok(cdk::types::ProofInfo {
  423. proof: info.proof.try_into().map_err(|e: FfiError| {
  424. cdk::cdk_database::Error::Database(e.to_string().into())
  425. })?,
  426. y: info.y.try_into().map_err(|e: FfiError| {
  427. cdk::cdk_database::Error::Database(e.to_string().into())
  428. })?,
  429. mint_url: info.mint_url.try_into().map_err(|e: FfiError| {
  430. cdk::cdk_database::Error::Database(e.to_string().into())
  431. })?,
  432. state: info.state.into(),
  433. spending_condition: info
  434. .spending_condition
  435. .map(|sc| sc.try_into())
  436. .transpose()
  437. .map_err(|e: FfiError| {
  438. cdk::cdk_database::Error::Database(e.to_string().into())
  439. })?,
  440. unit: info.unit.into(),
  441. used_by_operation: info
  442. .used_by_operation
  443. .map(|id| uuid::Uuid::parse_str(&id))
  444. .transpose()
  445. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?,
  446. created_by_operation: info
  447. .created_by_operation
  448. .map(|id| uuid::Uuid::parse_str(&id))
  449. .transpose()
  450. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?,
  451. })
  452. })
  453. .collect();
  454. cdk_result
  455. }
  456. async fn get_proofs_by_ys(
  457. &self,
  458. ys: Vec<cdk::nuts::PublicKey>,
  459. ) -> Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> {
  460. let ffi_ys: Vec<PublicKey> = ys.into_iter().map(Into::into).collect();
  461. let result = self
  462. .ffi_db
  463. .get_proofs_by_ys(ffi_ys)
  464. .await
  465. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  466. // Convert back to CDK ProofInfo
  467. let cdk_result: Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> = result
  468. .into_iter()
  469. .map(|info| {
  470. Ok(cdk::types::ProofInfo {
  471. proof: info.proof.try_into().map_err(|e: FfiError| {
  472. cdk::cdk_database::Error::Database(e.to_string().into())
  473. })?,
  474. y: info.y.try_into().map_err(|e: FfiError| {
  475. cdk::cdk_database::Error::Database(e.to_string().into())
  476. })?,
  477. mint_url: info.mint_url.try_into().map_err(|e: FfiError| {
  478. cdk::cdk_database::Error::Database(e.to_string().into())
  479. })?,
  480. state: info.state.into(),
  481. spending_condition: info
  482. .spending_condition
  483. .map(|sc| sc.try_into())
  484. .transpose()
  485. .map_err(|e: FfiError| {
  486. cdk::cdk_database::Error::Database(e.to_string().into())
  487. })?,
  488. unit: info.unit.into(),
  489. used_by_operation: info
  490. .used_by_operation
  491. .map(|id| uuid::Uuid::parse_str(&id))
  492. .transpose()
  493. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?,
  494. created_by_operation: info
  495. .created_by_operation
  496. .map(|id| uuid::Uuid::parse_str(&id))
  497. .transpose()
  498. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?,
  499. })
  500. })
  501. .collect();
  502. cdk_result
  503. }
  504. async fn get_balance(
  505. &self,
  506. mint_url: Option<cdk::mint_url::MintUrl>,
  507. unit: Option<cdk::nuts::CurrencyUnit>,
  508. state: Option<Vec<cdk::nuts::State>>,
  509. ) -> Result<u64, cdk::cdk_database::Error> {
  510. let ffi_mint_url = mint_url.map(Into::into);
  511. let ffi_unit = unit.map(Into::into);
  512. let ffi_state = state.map(|s| s.into_iter().map(Into::into).collect());
  513. self.ffi_db
  514. .get_balance(ffi_mint_url, ffi_unit, ffi_state)
  515. .await
  516. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  517. }
  518. // Transaction Management
  519. async fn get_transaction(
  520. &self,
  521. transaction_id: cdk::wallet::types::TransactionId,
  522. ) -> Result<Option<cdk::wallet::types::Transaction>, cdk::cdk_database::Error> {
  523. let ffi_id = transaction_id.into();
  524. let result = self
  525. .ffi_db
  526. .get_transaction(ffi_id)
  527. .await
  528. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  529. result
  530. .map(|tx| tx.try_into())
  531. .transpose()
  532. .map_err(|e: FfiError| cdk::cdk_database::Error::Database(e.to_string().into()))
  533. }
  534. async fn list_transactions(
  535. &self,
  536. mint_url: Option<cdk::mint_url::MintUrl>,
  537. direction: Option<cdk::wallet::types::TransactionDirection>,
  538. unit: Option<cdk::nuts::CurrencyUnit>,
  539. ) -> Result<Vec<cdk::wallet::types::Transaction>, cdk::cdk_database::Error> {
  540. let ffi_mint_url = mint_url.map(Into::into);
  541. let ffi_direction = direction.map(Into::into);
  542. let ffi_unit = unit.map(Into::into);
  543. let result = self
  544. .ffi_db
  545. .list_transactions(ffi_mint_url, ffi_direction, ffi_unit)
  546. .await
  547. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  548. result
  549. .into_iter()
  550. .map(|tx| tx.try_into())
  551. .collect::<Result<Vec<_>, FfiError>>()
  552. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  553. }
  554. // Write methods (non-transactional)
  555. async fn update_proofs(
  556. &self,
  557. added: Vec<cdk::types::ProofInfo>,
  558. removed_ys: Vec<cdk::nuts::PublicKey>,
  559. ) -> Result<(), cdk::cdk_database::Error> {
  560. let ffi_added: Vec<ProofInfo> = added.into_iter().map(Into::into).collect();
  561. let ffi_removed_ys: Vec<PublicKey> = removed_ys.into_iter().map(Into::into).collect();
  562. self.ffi_db
  563. .update_proofs(ffi_added, ffi_removed_ys)
  564. .await
  565. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  566. }
  567. async fn update_proofs_state(
  568. &self,
  569. ys: Vec<cdk::nuts::PublicKey>,
  570. state: cdk::nuts::State,
  571. ) -> Result<(), cdk::cdk_database::Error> {
  572. let ffi_ys: Vec<PublicKey> = ys.into_iter().map(Into::into).collect();
  573. let ffi_state = state.into();
  574. self.ffi_db
  575. .update_proofs_state(ffi_ys, ffi_state)
  576. .await
  577. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  578. }
  579. async fn add_transaction(
  580. &self,
  581. transaction: cdk::wallet::types::Transaction,
  582. ) -> Result<(), cdk::cdk_database::Error> {
  583. let ffi_transaction = transaction.into();
  584. self.ffi_db
  585. .add_transaction(ffi_transaction)
  586. .await
  587. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  588. }
  589. async fn update_mint_url(
  590. &self,
  591. old_mint_url: cdk::mint_url::MintUrl,
  592. new_mint_url: cdk::mint_url::MintUrl,
  593. ) -> Result<(), cdk::cdk_database::Error> {
  594. let ffi_old = old_mint_url.into();
  595. let ffi_new = new_mint_url.into();
  596. self.ffi_db
  597. .update_mint_url(ffi_old, ffi_new)
  598. .await
  599. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  600. }
  601. async fn increment_keyset_counter(
  602. &self,
  603. keyset_id: &cdk::nuts::Id,
  604. count: u32,
  605. ) -> Result<u32, cdk::cdk_database::Error> {
  606. let ffi_id = (*keyset_id).into();
  607. self.ffi_db
  608. .increment_keyset_counter(ffi_id, count)
  609. .await
  610. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  611. }
  612. async fn add_mint(
  613. &self,
  614. mint_url: cdk::mint_url::MintUrl,
  615. mint_info: Option<cdk::nuts::MintInfo>,
  616. ) -> Result<(), cdk::cdk_database::Error> {
  617. let ffi_mint_url = mint_url.into();
  618. let ffi_mint_info = mint_info.map(Into::into);
  619. self.ffi_db
  620. .add_mint(ffi_mint_url, ffi_mint_info)
  621. .await
  622. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  623. }
  624. async fn remove_mint(
  625. &self,
  626. mint_url: cdk::mint_url::MintUrl,
  627. ) -> Result<(), cdk::cdk_database::Error> {
  628. let ffi_mint_url = mint_url.into();
  629. self.ffi_db
  630. .remove_mint(ffi_mint_url)
  631. .await
  632. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  633. }
  634. async fn add_mint_keysets(
  635. &self,
  636. mint_url: cdk::mint_url::MintUrl,
  637. keysets: Vec<cdk::nuts::KeySetInfo>,
  638. ) -> Result<(), cdk::cdk_database::Error> {
  639. let ffi_mint_url = mint_url.into();
  640. let ffi_keysets: Vec<KeySetInfo> = keysets.into_iter().map(Into::into).collect();
  641. self.ffi_db
  642. .add_mint_keysets(ffi_mint_url, ffi_keysets)
  643. .await
  644. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  645. }
  646. async fn add_mint_quote(
  647. &self,
  648. quote: cdk::wallet::MintQuote,
  649. ) -> Result<(), cdk::cdk_database::Error> {
  650. let ffi_quote = quote.into();
  651. self.ffi_db
  652. .add_mint_quote(ffi_quote)
  653. .await
  654. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  655. }
  656. async fn remove_mint_quote(&self, quote_id: &str) -> Result<(), cdk::cdk_database::Error> {
  657. self.ffi_db
  658. .remove_mint_quote(quote_id.to_string())
  659. .await
  660. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  661. }
  662. async fn add_melt_quote(
  663. &self,
  664. quote: cdk::wallet::MeltQuote,
  665. ) -> Result<(), cdk::cdk_database::Error> {
  666. let ffi_quote = quote.into();
  667. self.ffi_db
  668. .add_melt_quote(ffi_quote)
  669. .await
  670. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  671. }
  672. async fn remove_melt_quote(&self, quote_id: &str) -> Result<(), cdk::cdk_database::Error> {
  673. self.ffi_db
  674. .remove_melt_quote(quote_id.to_string())
  675. .await
  676. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  677. }
  678. async fn add_keys(&self, keyset: cdk::nuts::KeySet) -> Result<(), cdk::cdk_database::Error> {
  679. let ffi_keyset: KeySet = keyset.into();
  680. self.ffi_db
  681. .add_keys(ffi_keyset)
  682. .await
  683. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  684. }
  685. async fn remove_keys(&self, id: &cdk::nuts::Id) -> Result<(), cdk::cdk_database::Error> {
  686. let ffi_id = (*id).into();
  687. self.ffi_db
  688. .remove_keys(ffi_id)
  689. .await
  690. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  691. }
  692. async fn remove_transaction(
  693. &self,
  694. transaction_id: cdk::wallet::types::TransactionId,
  695. ) -> Result<(), cdk::cdk_database::Error> {
  696. let ffi_id = transaction_id.into();
  697. self.ffi_db
  698. .remove_transaction(ffi_id)
  699. .await
  700. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  701. }
  702. async fn add_saga(&self, saga: WalletSaga) -> Result<(), cdk::cdk_database::Error> {
  703. let json = serde_json::to_string(&saga)
  704. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  705. self.ffi_db
  706. .add_saga(json)
  707. .await
  708. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  709. }
  710. async fn get_saga(
  711. &self,
  712. id: &uuid::Uuid,
  713. ) -> Result<Option<WalletSaga>, cdk::cdk_database::Error> {
  714. let json_opt = self
  715. .ffi_db
  716. .get_saga(id.to_string())
  717. .await
  718. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  719. match json_opt {
  720. Some(json) => {
  721. let saga: WalletSaga = serde_json::from_str(&json)
  722. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  723. Ok(Some(saga))
  724. }
  725. None => Ok(None),
  726. }
  727. }
  728. async fn update_saga(&self, saga: WalletSaga) -> Result<bool, cdk::cdk_database::Error> {
  729. let json = serde_json::to_string(&saga)
  730. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  731. self.ffi_db
  732. .update_saga(json)
  733. .await
  734. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  735. }
  736. async fn delete_saga(&self, id: &uuid::Uuid) -> Result<(), cdk::cdk_database::Error> {
  737. self.ffi_db
  738. .delete_saga(id.to_string())
  739. .await
  740. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  741. }
  742. async fn get_incomplete_sagas(&self) -> Result<Vec<WalletSaga>, cdk::cdk_database::Error> {
  743. let json_vec = self
  744. .ffi_db
  745. .get_incomplete_sagas()
  746. .await
  747. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  748. json_vec
  749. .into_iter()
  750. .map(|json| {
  751. serde_json::from_str(&json)
  752. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  753. })
  754. .collect()
  755. }
  756. async fn reserve_proofs(
  757. &self,
  758. ys: Vec<cdk::nuts::PublicKey>,
  759. operation_id: &uuid::Uuid,
  760. ) -> Result<(), cdk::cdk_database::Error> {
  761. let ffi_ys: Vec<PublicKey> = ys.into_iter().map(Into::into).collect();
  762. self.ffi_db
  763. .reserve_proofs(ffi_ys, operation_id.to_string())
  764. .await
  765. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  766. }
  767. async fn release_proofs(
  768. &self,
  769. operation_id: &uuid::Uuid,
  770. ) -> Result<(), cdk::cdk_database::Error> {
  771. self.ffi_db
  772. .release_proofs(operation_id.to_string())
  773. .await
  774. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  775. }
  776. async fn get_reserved_proofs(
  777. &self,
  778. operation_id: &uuid::Uuid,
  779. ) -> Result<Vec<cdk::types::ProofInfo>, cdk::cdk_database::Error> {
  780. let result = self
  781. .ffi_db
  782. .get_reserved_proofs(operation_id.to_string())
  783. .await
  784. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?;
  785. result
  786. .into_iter()
  787. .map(|info| {
  788. Ok(cdk::types::ProofInfo {
  789. proof: info.proof.try_into().map_err(|e: FfiError| {
  790. cdk::cdk_database::Error::Database(e.to_string().into())
  791. })?,
  792. y: info.y.try_into().map_err(|e: FfiError| {
  793. cdk::cdk_database::Error::Database(e.to_string().into())
  794. })?,
  795. mint_url: info.mint_url.try_into().map_err(|e: FfiError| {
  796. cdk::cdk_database::Error::Database(e.to_string().into())
  797. })?,
  798. state: info.state.into(),
  799. spending_condition: info
  800. .spending_condition
  801. .map(|sc| sc.try_into())
  802. .transpose()
  803. .map_err(|e: FfiError| {
  804. cdk::cdk_database::Error::Database(e.to_string().into())
  805. })?,
  806. unit: info.unit.into(),
  807. used_by_operation: info
  808. .used_by_operation
  809. .map(|id| uuid::Uuid::parse_str(&id))
  810. .transpose()
  811. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?,
  812. created_by_operation: info
  813. .created_by_operation
  814. .map(|id| uuid::Uuid::parse_str(&id))
  815. .transpose()
  816. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))?,
  817. })
  818. })
  819. .collect()
  820. }
  821. async fn reserve_melt_quote(
  822. &self,
  823. quote_id: &str,
  824. operation_id: &uuid::Uuid,
  825. ) -> Result<(), cdk::cdk_database::Error> {
  826. self.ffi_db
  827. .reserve_melt_quote(quote_id.to_string(), operation_id.to_string())
  828. .await
  829. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  830. }
  831. async fn release_melt_quote(
  832. &self,
  833. operation_id: &uuid::Uuid,
  834. ) -> Result<(), cdk::cdk_database::Error> {
  835. self.ffi_db
  836. .release_melt_quote(operation_id.to_string())
  837. .await
  838. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  839. }
  840. async fn reserve_mint_quote(
  841. &self,
  842. quote_id: &str,
  843. operation_id: &uuid::Uuid,
  844. ) -> Result<(), cdk::cdk_database::Error> {
  845. self.ffi_db
  846. .reserve_mint_quote(quote_id.to_string(), operation_id.to_string())
  847. .await
  848. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  849. }
  850. async fn release_mint_quote(
  851. &self,
  852. operation_id: &uuid::Uuid,
  853. ) -> Result<(), cdk::cdk_database::Error> {
  854. self.ffi_db
  855. .release_mint_quote(operation_id.to_string())
  856. .await
  857. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  858. }
  859. async fn kv_write(
  860. &self,
  861. primary_namespace: &str,
  862. secondary_namespace: &str,
  863. key: &str,
  864. value: &[u8],
  865. ) -> Result<(), cdk::cdk_database::Error> {
  866. self.ffi_db
  867. .kv_write(
  868. primary_namespace.to_string(),
  869. secondary_namespace.to_string(),
  870. key.to_string(),
  871. value.to_vec(),
  872. )
  873. .await
  874. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  875. }
  876. async fn kv_remove(
  877. &self,
  878. primary_namespace: &str,
  879. secondary_namespace: &str,
  880. key: &str,
  881. ) -> Result<(), cdk::cdk_database::Error> {
  882. self.ffi_db
  883. .kv_remove(
  884. primary_namespace.to_string(),
  885. secondary_namespace.to_string(),
  886. key.to_string(),
  887. )
  888. .await
  889. .map_err(|e| cdk::cdk_database::Error::Database(e.to_string().into()))
  890. }
  891. }
  892. pub(crate) struct FfiWalletSQLDatabase<RM>
  893. where
  894. RM: DatabasePool + 'static,
  895. {
  896. inner: SQLWalletDatabase<RM>,
  897. }
  898. impl<RM> FfiWalletSQLDatabase<RM>
  899. where
  900. RM: DatabasePool + 'static,
  901. {
  902. /// Creates a new instance
  903. pub fn new(inner: SQLWalletDatabase<RM>) -> Arc<Self> {
  904. Arc::new(Self { inner })
  905. }
  906. }
  907. // Implement WalletDatabase trait - all read and write methods
  908. #[async_trait::async_trait]
  909. impl<RM> WalletDatabase for FfiWalletSQLDatabase<RM>
  910. where
  911. RM: DatabasePool + 'static,
  912. {
  913. // ========== Read methods ==========
  914. async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, FfiError> {
  915. let cdk_ys: Vec<cdk::nuts::PublicKey> = ys
  916. .into_iter()
  917. .map(|y| y.try_into())
  918. .collect::<Result<Vec<_>, FfiError>>()?;
  919. let result = self
  920. .inner
  921. .get_proofs_by_ys(cdk_ys)
  922. .await
  923. .map_err(FfiError::internal)?;
  924. Ok(result.into_iter().map(Into::into).collect())
  925. }
  926. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
  927. let cdk_mint_url = mint_url.try_into()?;
  928. let result = self
  929. .inner
  930. .get_mint(cdk_mint_url)
  931. .await
  932. .map_err(FfiError::internal)?;
  933. Ok(result.map(Into::into))
  934. }
  935. async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, FfiError> {
  936. let result = self.inner.get_mints().await.map_err(FfiError::internal)?;
  937. Ok(result
  938. .into_iter()
  939. .map(|(k, v)| (k.into(), v.map(Into::into)))
  940. .collect())
  941. }
  942. async fn get_mint_keysets(
  943. &self,
  944. mint_url: MintUrl,
  945. ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
  946. let cdk_mint_url = mint_url.try_into()?;
  947. let result = self
  948. .inner
  949. .get_mint_keysets(cdk_mint_url)
  950. .await
  951. .map_err(FfiError::internal)?;
  952. Ok(result.map(|keysets| keysets.into_iter().map(Into::into).collect()))
  953. }
  954. async fn get_keyset_by_id(&self, keyset_id: Id) -> Result<Option<KeySetInfo>, FfiError> {
  955. let cdk_id = keyset_id.into();
  956. let result = self
  957. .inner
  958. .get_keyset_by_id(&cdk_id)
  959. .await
  960. .map_err(FfiError::internal)?;
  961. Ok(result.map(Into::into))
  962. }
  963. async fn get_mint_quote(&self, quote_id: String) -> Result<Option<MintQuote>, FfiError> {
  964. let result = self
  965. .inner
  966. .get_mint_quote(&quote_id)
  967. .await
  968. .map_err(FfiError::internal)?;
  969. Ok(result.map(|q| q.into()))
  970. }
  971. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  972. let result = self
  973. .inner
  974. .get_mint_quotes()
  975. .await
  976. .map_err(FfiError::internal)?;
  977. Ok(result.into_iter().map(|q| q.into()).collect())
  978. }
  979. async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  980. let result = self
  981. .inner
  982. .get_unissued_mint_quotes()
  983. .await
  984. .map_err(FfiError::internal)?;
  985. Ok(result.into_iter().map(|q| q.into()).collect())
  986. }
  987. async fn get_melt_quote(&self, quote_id: String) -> Result<Option<MeltQuote>, FfiError> {
  988. let result = self
  989. .inner
  990. .get_melt_quote(&quote_id)
  991. .await
  992. .map_err(FfiError::internal)?;
  993. Ok(result.map(|q| q.into()))
  994. }
  995. async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
  996. let result = self
  997. .inner
  998. .get_melt_quotes()
  999. .await
  1000. .map_err(FfiError::internal)?;
  1001. Ok(result.into_iter().map(|q| q.into()).collect())
  1002. }
  1003. async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
  1004. let cdk_id = id.into();
  1005. let result = self
  1006. .inner
  1007. .get_keys(&cdk_id)
  1008. .await
  1009. .map_err(FfiError::internal)?;
  1010. Ok(result.map(Into::into))
  1011. }
  1012. async fn get_proofs(
  1013. &self,
  1014. mint_url: Option<MintUrl>,
  1015. unit: Option<CurrencyUnit>,
  1016. state: Option<Vec<ProofState>>,
  1017. spending_conditions: Option<Vec<SpendingConditions>>,
  1018. ) -> Result<Vec<ProofInfo>, FfiError> {
  1019. let cdk_mint_url = mint_url.map(|u| u.try_into()).transpose()?;
  1020. let cdk_unit = unit.map(Into::into);
  1021. let cdk_state = state.map(|s| s.into_iter().map(Into::into).collect());
  1022. let cdk_spending_conditions: Option<Vec<cdk::nuts::SpendingConditions>> =
  1023. spending_conditions
  1024. .map(|sc| {
  1025. sc.into_iter()
  1026. .map(|c| c.try_into())
  1027. .collect::<Result<Vec<_>, FfiError>>()
  1028. })
  1029. .transpose()?;
  1030. let result = self
  1031. .inner
  1032. .get_proofs(cdk_mint_url, cdk_unit, cdk_state, cdk_spending_conditions)
  1033. .await
  1034. .map_err(FfiError::internal)?;
  1035. Ok(result.into_iter().map(Into::into).collect())
  1036. }
  1037. async fn get_balance(
  1038. &self,
  1039. mint_url: Option<MintUrl>,
  1040. unit: Option<CurrencyUnit>,
  1041. state: Option<Vec<ProofState>>,
  1042. ) -> Result<u64, FfiError> {
  1043. let cdk_mint_url = mint_url.map(|u| u.try_into()).transpose()?;
  1044. let cdk_unit = unit.map(Into::into);
  1045. let cdk_state = state.map(|s| s.into_iter().map(Into::into).collect());
  1046. self.inner
  1047. .get_balance(cdk_mint_url, cdk_unit, cdk_state)
  1048. .await
  1049. .map_err(FfiError::internal)
  1050. }
  1051. async fn get_transaction(
  1052. &self,
  1053. transaction_id: TransactionId,
  1054. ) -> Result<Option<Transaction>, FfiError> {
  1055. let cdk_id = transaction_id.try_into()?;
  1056. let result = self
  1057. .inner
  1058. .get_transaction(cdk_id)
  1059. .await
  1060. .map_err(FfiError::internal)?;
  1061. Ok(result.map(Into::into))
  1062. }
  1063. async fn list_transactions(
  1064. &self,
  1065. mint_url: Option<MintUrl>,
  1066. direction: Option<TransactionDirection>,
  1067. unit: Option<CurrencyUnit>,
  1068. ) -> Result<Vec<Transaction>, FfiError> {
  1069. let cdk_mint_url = mint_url.map(|u| u.try_into()).transpose()?;
  1070. let cdk_direction = direction.map(Into::into);
  1071. let cdk_unit = unit.map(Into::into);
  1072. let result = self
  1073. .inner
  1074. .list_transactions(cdk_mint_url, cdk_direction, cdk_unit)
  1075. .await
  1076. .map_err(FfiError::internal)?;
  1077. Ok(result.into_iter().map(Into::into).collect())
  1078. }
  1079. async fn kv_read(
  1080. &self,
  1081. primary_namespace: String,
  1082. secondary_namespace: String,
  1083. key: String,
  1084. ) -> Result<Option<Vec<u8>>, FfiError> {
  1085. self.inner
  1086. .kv_read(&primary_namespace, &secondary_namespace, &key)
  1087. .await
  1088. .map_err(FfiError::internal)
  1089. }
  1090. async fn kv_list(
  1091. &self,
  1092. primary_namespace: String,
  1093. secondary_namespace: String,
  1094. ) -> Result<Vec<String>, FfiError> {
  1095. self.inner
  1096. .kv_list(&primary_namespace, &secondary_namespace)
  1097. .await
  1098. .map_err(FfiError::internal)
  1099. }
  1100. async fn kv_write(
  1101. &self,
  1102. primary_namespace: String,
  1103. secondary_namespace: String,
  1104. key: String,
  1105. value: Vec<u8>,
  1106. ) -> Result<(), FfiError> {
  1107. self.inner
  1108. .kv_write(&primary_namespace, &secondary_namespace, &key, &value)
  1109. .await
  1110. .map_err(FfiError::internal)
  1111. }
  1112. async fn kv_remove(
  1113. &self,
  1114. primary_namespace: String,
  1115. secondary_namespace: String,
  1116. key: String,
  1117. ) -> Result<(), FfiError> {
  1118. self.inner
  1119. .kv_remove(&primary_namespace, &secondary_namespace, &key)
  1120. .await
  1121. .map_err(FfiError::internal)
  1122. }
  1123. // ========== Write methods ==========
  1124. async fn update_proofs(
  1125. &self,
  1126. added: Vec<ProofInfo>,
  1127. removed_ys: Vec<PublicKey>,
  1128. ) -> Result<(), FfiError> {
  1129. let cdk_added: Result<Vec<cdk::types::ProofInfo>, FfiError> = added
  1130. .into_iter()
  1131. .map(|info| {
  1132. Ok::<cdk::types::ProofInfo, FfiError>(cdk::types::ProofInfo {
  1133. proof: info.proof.try_into()?,
  1134. y: info.y.try_into()?,
  1135. mint_url: info.mint_url.try_into()?,
  1136. state: info.state.into(),
  1137. spending_condition: info
  1138. .spending_condition
  1139. .map(|sc| sc.try_into())
  1140. .transpose()?,
  1141. unit: info.unit.into(),
  1142. used_by_operation: info
  1143. .used_by_operation
  1144. .map(|id| uuid::Uuid::parse_str(&id))
  1145. .transpose()
  1146. .map_err(|e| FfiError::internal(e.to_string()))?,
  1147. created_by_operation: info
  1148. .created_by_operation
  1149. .map(|id| uuid::Uuid::parse_str(&id))
  1150. .transpose()
  1151. .map_err(|e| FfiError::internal(e.to_string()))?,
  1152. })
  1153. })
  1154. .collect();
  1155. let cdk_added = cdk_added?;
  1156. let cdk_removed_ys: Result<Vec<cdk::nuts::PublicKey>, FfiError> =
  1157. removed_ys.into_iter().map(|pk| pk.try_into()).collect();
  1158. let cdk_removed_ys = cdk_removed_ys?;
  1159. self.inner
  1160. .update_proofs(cdk_added, cdk_removed_ys)
  1161. .await
  1162. .map_err(FfiError::internal)
  1163. }
  1164. async fn update_proofs_state(
  1165. &self,
  1166. ys: Vec<PublicKey>,
  1167. state: ProofState,
  1168. ) -> Result<(), FfiError> {
  1169. let cdk_ys: Result<Vec<cdk::nuts::PublicKey>, FfiError> =
  1170. ys.into_iter().map(|pk| pk.try_into()).collect();
  1171. let cdk_ys = cdk_ys?;
  1172. let cdk_state = state.into();
  1173. self.inner
  1174. .update_proofs_state(cdk_ys, cdk_state)
  1175. .await
  1176. .map_err(FfiError::internal)
  1177. }
  1178. async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
  1179. let cdk_transaction: cdk::wallet::types::Transaction = transaction.try_into()?;
  1180. self.inner
  1181. .add_transaction(cdk_transaction)
  1182. .await
  1183. .map_err(FfiError::internal)
  1184. }
  1185. async fn remove_transaction(&self, transaction_id: TransactionId) -> Result<(), FfiError> {
  1186. let cdk_id = transaction_id.try_into()?;
  1187. self.inner
  1188. .remove_transaction(cdk_id)
  1189. .await
  1190. .map_err(FfiError::internal)
  1191. }
  1192. async fn update_mint_url(
  1193. &self,
  1194. old_mint_url: MintUrl,
  1195. new_mint_url: MintUrl,
  1196. ) -> Result<(), FfiError> {
  1197. let cdk_old = old_mint_url.try_into()?;
  1198. let cdk_new = new_mint_url.try_into()?;
  1199. self.inner
  1200. .update_mint_url(cdk_old, cdk_new)
  1201. .await
  1202. .map_err(FfiError::internal)
  1203. }
  1204. async fn increment_keyset_counter(&self, keyset_id: Id, count: u32) -> Result<u32, FfiError> {
  1205. let cdk_id = keyset_id.into();
  1206. self.inner
  1207. .increment_keyset_counter(&cdk_id, count)
  1208. .await
  1209. .map_err(FfiError::internal)
  1210. }
  1211. async fn add_mint(
  1212. &self,
  1213. mint_url: MintUrl,
  1214. mint_info: Option<MintInfo>,
  1215. ) -> Result<(), FfiError> {
  1216. let cdk_mint_url = mint_url.try_into()?;
  1217. let cdk_mint_info = mint_info.map(Into::into);
  1218. self.inner
  1219. .add_mint(cdk_mint_url, cdk_mint_info)
  1220. .await
  1221. .map_err(FfiError::internal)
  1222. }
  1223. async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
  1224. let cdk_mint_url = mint_url.try_into()?;
  1225. self.inner
  1226. .remove_mint(cdk_mint_url)
  1227. .await
  1228. .map_err(FfiError::internal)
  1229. }
  1230. async fn add_mint_keysets(
  1231. &self,
  1232. mint_url: MintUrl,
  1233. keysets: Vec<KeySetInfo>,
  1234. ) -> Result<(), FfiError> {
  1235. let cdk_mint_url = mint_url.try_into()?;
  1236. let cdk_keysets: Vec<cdk::nuts::KeySetInfo> = keysets.into_iter().map(Into::into).collect();
  1237. self.inner
  1238. .add_mint_keysets(cdk_mint_url, cdk_keysets)
  1239. .await
  1240. .map_err(FfiError::internal)
  1241. }
  1242. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
  1243. let cdk_quote = quote.try_into()?;
  1244. self.inner
  1245. .add_mint_quote(cdk_quote)
  1246. .await
  1247. .map_err(FfiError::internal)
  1248. }
  1249. async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1250. self.inner
  1251. .remove_mint_quote(&quote_id)
  1252. .await
  1253. .map_err(FfiError::internal)
  1254. }
  1255. async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
  1256. let cdk_quote = quote.try_into()?;
  1257. self.inner
  1258. .add_melt_quote(cdk_quote)
  1259. .await
  1260. .map_err(FfiError::internal)
  1261. }
  1262. async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1263. self.inner
  1264. .remove_melt_quote(&quote_id)
  1265. .await
  1266. .map_err(FfiError::internal)
  1267. }
  1268. async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
  1269. let cdk_keyset: cdk::nuts::KeySet = keyset.try_into()?;
  1270. self.inner
  1271. .add_keys(cdk_keyset)
  1272. .await
  1273. .map_err(FfiError::internal)
  1274. }
  1275. async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
  1276. let cdk_id = id.into();
  1277. self.inner
  1278. .remove_keys(&cdk_id)
  1279. .await
  1280. .map_err(FfiError::internal)
  1281. }
  1282. // ========== Saga management methods ==========
  1283. async fn add_saga(&self, saga_json: String) -> Result<(), FfiError> {
  1284. let saga: WalletSaga = serde_json::from_str(&saga_json).map_err(FfiError::internal)?;
  1285. self.inner.add_saga(saga).await.map_err(FfiError::internal)
  1286. }
  1287. async fn get_saga(&self, id: String) -> Result<Option<String>, FfiError> {
  1288. let id = uuid::Uuid::parse_str(&id).map_err(FfiError::internal)?;
  1289. let result = self.inner.get_saga(&id).await.map_err(FfiError::internal)?;
  1290. match result {
  1291. Some(saga) => {
  1292. let json = serde_json::to_string(&saga).map_err(FfiError::internal)?;
  1293. Ok(Some(json))
  1294. }
  1295. None => Ok(None),
  1296. }
  1297. }
  1298. async fn update_saga(&self, saga_json: String) -> Result<bool, FfiError> {
  1299. let saga: WalletSaga = serde_json::from_str(&saga_json).map_err(FfiError::internal)?;
  1300. self.inner
  1301. .update_saga(saga)
  1302. .await
  1303. .map_err(FfiError::internal)
  1304. }
  1305. async fn delete_saga(&self, id: String) -> Result<(), FfiError> {
  1306. let id = uuid::Uuid::parse_str(&id).map_err(FfiError::internal)?;
  1307. self.inner
  1308. .delete_saga(&id)
  1309. .await
  1310. .map_err(FfiError::internal)
  1311. }
  1312. async fn get_incomplete_sagas(&self) -> Result<Vec<String>, FfiError> {
  1313. let result = self
  1314. .inner
  1315. .get_incomplete_sagas()
  1316. .await
  1317. .map_err(FfiError::internal)?;
  1318. result
  1319. .into_iter()
  1320. .map(|saga| serde_json::to_string(&saga).map_err(FfiError::internal))
  1321. .collect()
  1322. }
  1323. // ========== Proof reservation methods ==========
  1324. async fn reserve_proofs(
  1325. &self,
  1326. ys: Vec<PublicKey>,
  1327. operation_id: String,
  1328. ) -> Result<(), FfiError> {
  1329. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1330. let cdk_ys: Result<Vec<cdk::nuts::PublicKey>, FfiError> =
  1331. ys.into_iter().map(|pk| pk.try_into()).collect();
  1332. let cdk_ys = cdk_ys?;
  1333. self.inner
  1334. .reserve_proofs(cdk_ys, &operation_id)
  1335. .await
  1336. .map_err(FfiError::internal)
  1337. }
  1338. async fn release_proofs(&self, operation_id: String) -> Result<(), FfiError> {
  1339. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1340. self.inner
  1341. .release_proofs(&operation_id)
  1342. .await
  1343. .map_err(FfiError::internal)
  1344. }
  1345. async fn get_reserved_proofs(&self, operation_id: String) -> Result<Vec<ProofInfo>, FfiError> {
  1346. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1347. let result = self
  1348. .inner
  1349. .get_reserved_proofs(&operation_id)
  1350. .await
  1351. .map_err(FfiError::internal)?;
  1352. Ok(result.into_iter().map(Into::into).collect())
  1353. }
  1354. // ========== Quote reservation methods ==========
  1355. async fn reserve_melt_quote(
  1356. &self,
  1357. quote_id: String,
  1358. operation_id: String,
  1359. ) -> Result<(), FfiError> {
  1360. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1361. self.inner
  1362. .reserve_melt_quote(&quote_id, &operation_id)
  1363. .await
  1364. .map_err(FfiError::internal)
  1365. }
  1366. async fn release_melt_quote(&self, operation_id: String) -> Result<(), FfiError> {
  1367. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1368. self.inner
  1369. .release_melt_quote(&operation_id)
  1370. .await
  1371. .map_err(FfiError::internal)
  1372. }
  1373. async fn reserve_mint_quote(
  1374. &self,
  1375. quote_id: String,
  1376. operation_id: String,
  1377. ) -> Result<(), FfiError> {
  1378. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1379. self.inner
  1380. .reserve_mint_quote(&quote_id, &operation_id)
  1381. .await
  1382. .map_err(FfiError::internal)
  1383. }
  1384. async fn release_mint_quote(&self, operation_id: String) -> Result<(), FfiError> {
  1385. let operation_id = uuid::Uuid::parse_str(&operation_id).map_err(FfiError::internal)?;
  1386. self.inner
  1387. .release_mint_quote(&operation_id)
  1388. .await
  1389. .map_err(FfiError::internal)
  1390. }
  1391. }
  1392. /// Macro to implement WalletDatabase for wrapper types that delegate to an inner FfiWalletSQLDatabase.
  1393. /// This eliminates duplication between SQLite and Postgres FFI implementations.
  1394. ///
  1395. /// Requirements: The following types must be in scope where this macro is invoked:
  1396. /// - WalletDatabase, FfiError, PublicKey, ProofInfo, MintUrl, MintInfo, KeySetInfo, Id,
  1397. /// MintQuote, MeltQuote, Keys, CurrencyUnit, ProofState, SpendingConditions, Transaction,
  1398. /// TransactionId, TransactionDirection, KeySet
  1399. /// - std::collections::HashMap
  1400. #[macro_export]
  1401. macro_rules! impl_ffi_wallet_database {
  1402. ($wrapper_type:ty) => {
  1403. #[uniffi::export(async_runtime = "tokio")]
  1404. #[async_trait::async_trait]
  1405. impl WalletDatabase for $wrapper_type {
  1406. // ========== Read methods ==========
  1407. async fn get_proofs_by_ys(
  1408. &self,
  1409. ys: Vec<PublicKey>,
  1410. ) -> Result<Vec<ProofInfo>, FfiError> {
  1411. self.inner.get_proofs_by_ys(ys).await
  1412. }
  1413. async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
  1414. self.inner.get_mint(mint_url).await
  1415. }
  1416. async fn get_mints(
  1417. &self,
  1418. ) -> Result<std::collections::HashMap<MintUrl, Option<MintInfo>>, FfiError> {
  1419. self.inner.get_mints().await
  1420. }
  1421. async fn get_mint_keysets(
  1422. &self,
  1423. mint_url: MintUrl,
  1424. ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
  1425. self.inner.get_mint_keysets(mint_url).await
  1426. }
  1427. async fn get_keyset_by_id(
  1428. &self,
  1429. keyset_id: Id,
  1430. ) -> Result<Option<KeySetInfo>, FfiError> {
  1431. self.inner.get_keyset_by_id(keyset_id).await
  1432. }
  1433. async fn get_mint_quote(
  1434. &self,
  1435. quote_id: String,
  1436. ) -> Result<Option<MintQuote>, FfiError> {
  1437. self.inner.get_mint_quote(quote_id).await
  1438. }
  1439. async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  1440. self.inner.get_mint_quotes().await
  1441. }
  1442. async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
  1443. self.inner.get_unissued_mint_quotes().await
  1444. }
  1445. async fn get_melt_quote(
  1446. &self,
  1447. quote_id: String,
  1448. ) -> Result<Option<MeltQuote>, FfiError> {
  1449. self.inner.get_melt_quote(quote_id).await
  1450. }
  1451. async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
  1452. self.inner.get_melt_quotes().await
  1453. }
  1454. async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
  1455. self.inner.get_keys(id).await
  1456. }
  1457. async fn get_proofs(
  1458. &self,
  1459. mint_url: Option<MintUrl>,
  1460. unit: Option<CurrencyUnit>,
  1461. state: Option<Vec<ProofState>>,
  1462. spending_conditions: Option<Vec<SpendingConditions>>,
  1463. ) -> Result<Vec<ProofInfo>, FfiError> {
  1464. self.inner
  1465. .get_proofs(mint_url, unit, state, spending_conditions)
  1466. .await
  1467. }
  1468. async fn get_balance(
  1469. &self,
  1470. mint_url: Option<MintUrl>,
  1471. unit: Option<CurrencyUnit>,
  1472. state: Option<Vec<ProofState>>,
  1473. ) -> Result<u64, FfiError> {
  1474. self.inner.get_balance(mint_url, unit, state).await
  1475. }
  1476. async fn get_transaction(
  1477. &self,
  1478. transaction_id: TransactionId,
  1479. ) -> Result<Option<Transaction>, FfiError> {
  1480. self.inner.get_transaction(transaction_id).await
  1481. }
  1482. async fn list_transactions(
  1483. &self,
  1484. mint_url: Option<MintUrl>,
  1485. direction: Option<TransactionDirection>,
  1486. unit: Option<CurrencyUnit>,
  1487. ) -> Result<Vec<Transaction>, FfiError> {
  1488. self.inner
  1489. .list_transactions(mint_url, direction, unit)
  1490. .await
  1491. }
  1492. async fn kv_read(
  1493. &self,
  1494. primary_namespace: String,
  1495. secondary_namespace: String,
  1496. key: String,
  1497. ) -> Result<Option<Vec<u8>>, FfiError> {
  1498. self.inner
  1499. .kv_read(primary_namespace, secondary_namespace, key)
  1500. .await
  1501. }
  1502. async fn kv_list(
  1503. &self,
  1504. primary_namespace: String,
  1505. secondary_namespace: String,
  1506. ) -> Result<Vec<String>, FfiError> {
  1507. self.inner
  1508. .kv_list(primary_namespace, secondary_namespace)
  1509. .await
  1510. }
  1511. async fn kv_write(
  1512. &self,
  1513. primary_namespace: String,
  1514. secondary_namespace: String,
  1515. key: String,
  1516. value: Vec<u8>,
  1517. ) -> Result<(), FfiError> {
  1518. self.inner
  1519. .kv_write(primary_namespace, secondary_namespace, key, value)
  1520. .await
  1521. }
  1522. async fn kv_remove(
  1523. &self,
  1524. primary_namespace: String,
  1525. secondary_namespace: String,
  1526. key: String,
  1527. ) -> Result<(), FfiError> {
  1528. self.inner
  1529. .kv_remove(primary_namespace, secondary_namespace, key)
  1530. .await
  1531. }
  1532. // ========== Write methods ==========
  1533. async fn update_proofs(
  1534. &self,
  1535. added: Vec<ProofInfo>,
  1536. removed_ys: Vec<PublicKey>,
  1537. ) -> Result<(), FfiError> {
  1538. self.inner.update_proofs(added, removed_ys).await
  1539. }
  1540. async fn update_proofs_state(
  1541. &self,
  1542. ys: Vec<PublicKey>,
  1543. state: ProofState,
  1544. ) -> Result<(), FfiError> {
  1545. self.inner.update_proofs_state(ys, state).await
  1546. }
  1547. async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
  1548. self.inner.add_transaction(transaction).await
  1549. }
  1550. async fn remove_transaction(
  1551. &self,
  1552. transaction_id: TransactionId,
  1553. ) -> Result<(), FfiError> {
  1554. self.inner.remove_transaction(transaction_id).await
  1555. }
  1556. async fn update_mint_url(
  1557. &self,
  1558. old_mint_url: MintUrl,
  1559. new_mint_url: MintUrl,
  1560. ) -> Result<(), FfiError> {
  1561. self.inner.update_mint_url(old_mint_url, new_mint_url).await
  1562. }
  1563. async fn increment_keyset_counter(
  1564. &self,
  1565. keyset_id: Id,
  1566. count: u32,
  1567. ) -> Result<u32, FfiError> {
  1568. self.inner.increment_keyset_counter(keyset_id, count).await
  1569. }
  1570. async fn add_mint(
  1571. &self,
  1572. mint_url: MintUrl,
  1573. mint_info: Option<MintInfo>,
  1574. ) -> Result<(), FfiError> {
  1575. self.inner.add_mint(mint_url, mint_info).await
  1576. }
  1577. async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
  1578. self.inner.remove_mint(mint_url).await
  1579. }
  1580. async fn add_mint_keysets(
  1581. &self,
  1582. mint_url: MintUrl,
  1583. keysets: Vec<KeySetInfo>,
  1584. ) -> Result<(), FfiError> {
  1585. self.inner.add_mint_keysets(mint_url, keysets).await
  1586. }
  1587. async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
  1588. self.inner.add_mint_quote(quote).await
  1589. }
  1590. async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1591. self.inner.remove_mint_quote(quote_id).await
  1592. }
  1593. async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
  1594. self.inner.add_melt_quote(quote).await
  1595. }
  1596. async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
  1597. self.inner.remove_melt_quote(quote_id).await
  1598. }
  1599. async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
  1600. self.inner.add_keys(keyset).await
  1601. }
  1602. async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
  1603. self.inner.remove_keys(id).await
  1604. }
  1605. // ========== Saga management methods ==========
  1606. async fn add_saga(&self, saga_json: String) -> Result<(), FfiError> {
  1607. self.inner.add_saga(saga_json).await
  1608. }
  1609. async fn get_saga(&self, id: String) -> Result<Option<String>, FfiError> {
  1610. self.inner.get_saga(id).await
  1611. }
  1612. async fn update_saga(&self, saga_json: String) -> Result<bool, FfiError> {
  1613. self.inner.update_saga(saga_json).await
  1614. }
  1615. async fn delete_saga(&self, id: String) -> Result<(), FfiError> {
  1616. self.inner.delete_saga(id).await
  1617. }
  1618. async fn get_incomplete_sagas(&self) -> Result<Vec<String>, FfiError> {
  1619. self.inner.get_incomplete_sagas().await
  1620. }
  1621. // ========== Proof reservation methods ==========
  1622. async fn reserve_proofs(
  1623. &self,
  1624. ys: Vec<PublicKey>,
  1625. operation_id: String,
  1626. ) -> Result<(), FfiError> {
  1627. self.inner.reserve_proofs(ys, operation_id).await
  1628. }
  1629. async fn release_proofs(&self, operation_id: String) -> Result<(), FfiError> {
  1630. self.inner.release_proofs(operation_id).await
  1631. }
  1632. async fn get_reserved_proofs(
  1633. &self,
  1634. operation_id: String,
  1635. ) -> Result<Vec<ProofInfo>, FfiError> {
  1636. self.inner.get_reserved_proofs(operation_id).await
  1637. }
  1638. // ========== Quote reservation methods ==========
  1639. async fn reserve_melt_quote(
  1640. &self,
  1641. quote_id: String,
  1642. operation_id: String,
  1643. ) -> Result<(), FfiError> {
  1644. self.inner.reserve_melt_quote(quote_id, operation_id).await
  1645. }
  1646. async fn release_melt_quote(&self, operation_id: String) -> Result<(), FfiError> {
  1647. self.inner.release_melt_quote(operation_id).await
  1648. }
  1649. async fn reserve_mint_quote(
  1650. &self,
  1651. quote_id: String,
  1652. operation_id: String,
  1653. ) -> Result<(), FfiError> {
  1654. self.inner.reserve_mint_quote(quote_id, operation_id).await
  1655. }
  1656. async fn release_mint_quote(&self, operation_id: String) -> Result<(), FfiError> {
  1657. self.inner.release_mint_quote(operation_id).await
  1658. }
  1659. }
  1660. };
  1661. }
  1662. /// FFI-safe database type enum
  1663. #[derive(uniffi::Enum, Clone)]
  1664. pub enum WalletDbBackend {
  1665. Sqlite {
  1666. path: String,
  1667. },
  1668. #[cfg(feature = "postgres")]
  1669. Postgres {
  1670. url: String,
  1671. },
  1672. }
  1673. /// Factory helpers returning a CDK wallet database behind the FFI trait
  1674. #[uniffi::export]
  1675. pub fn create_wallet_db(backend: WalletDbBackend) -> Result<Arc<dyn WalletDatabase>, FfiError> {
  1676. match backend {
  1677. WalletDbBackend::Sqlite { path } => {
  1678. let sqlite = WalletSqliteDatabase::new(path)?;
  1679. Ok(sqlite as Arc<dyn WalletDatabase>)
  1680. }
  1681. #[cfg(feature = "postgres")]
  1682. WalletDbBackend::Postgres { url } => {
  1683. let pg = WalletPostgresDatabase::new(url)?;
  1684. Ok(pg as Arc<dyn WalletDatabase>)
  1685. }
  1686. }
  1687. }
  1688. /// Helper function to create a CDK database from the FFI trait
  1689. pub fn create_cdk_database_from_ffi(
  1690. ffi_db: Arc<dyn WalletDatabase>,
  1691. ) -> Arc<dyn CdkWalletDatabase<cdk::cdk_database::Error> + Send + Sync> {
  1692. Arc::new(WalletDatabaseBridge::new(ffi_db))
  1693. }