cdk_ffi/
wallet_repository.rs1use std::collections::HashMap;
4use std::sync::Arc;
5
6use bip39::Mnemonic;
7use cdk::wallet::wallet_repository::{
8 WalletRepository as CdkWalletRepository, WalletRepositoryBuilder,
9};
10
11use crate::error::FfiError;
12use crate::types::*;
13
14#[derive(uniffi::Object)]
16pub struct WalletRepository {
17 inner: Arc<CdkWalletRepository>,
18}
19
20#[uniffi::export(async_runtime = "tokio")]
21impl WalletRepository {
22 #[uniffi::constructor]
31 pub fn new(mnemonic: String, store: crate::database::WalletStore) -> Result<Self, FfiError> {
32 let db = crate::database::resolve_wallet_store(store)?;
33
34 let m = Mnemonic::parse(&mnemonic)
36 .map_err(|e| FfiError::internal(format!("Invalid mnemonic: {}", e)))?;
37 let seed = m.to_seed_normalized("");
38
39 let localstore = crate::database::create_cdk_database_from_ffi(db);
41
42 let rt = crate::runtime::RuntimeGuard::new().map_err(FfiError::internal)?;
43 let wallet = rt.block_on(async move {
44 WalletRepositoryBuilder::new()
45 .localstore(localstore)
46 .seed(seed)
47 .build()
48 .await
49 })?;
50
51 Ok(Self {
52 inner: Arc::new(wallet),
53 })
54 }
55
56 #[uniffi::constructor]
62 pub fn new_with_proxy(
63 mnemonic: String,
64 store: crate::database::WalletStore,
65 proxy_url: String,
66 ) -> Result<Self, FfiError> {
67 let db = crate::database::resolve_wallet_store(store)?;
68
69 let m = Mnemonic::parse(&mnemonic)
71 .map_err(|e| FfiError::internal(format!("Invalid mnemonic: {}", e)))?;
72 let seed = m.to_seed_normalized("");
73
74 let localstore = crate::database::create_cdk_database_from_ffi(db);
76
77 let proxy_url = url::Url::parse(&proxy_url)
79 .map_err(|e| FfiError::internal(format!("Invalid URL: {}", e)))?;
80
81 let rt = crate::runtime::RuntimeGuard::new().map_err(FfiError::internal)?;
82 let wallet = rt.block_on(async move {
83 WalletRepositoryBuilder::new()
84 .localstore(localstore)
85 .seed(seed)
86 .proxy_url(proxy_url)
87 .build()
88 .await
89 })?;
90
91 Ok(Self {
92 inner: Arc::new(wallet),
93 })
94 }
95
96 pub async fn set_metadata_cache_ttl_for_mint(
106 &self,
107 mint_url: MintUrl,
108 ttl_secs: Option<u64>,
109 ) -> Result<(), FfiError> {
110 let cdk_mint_url: cdk::mint_url::MintUrl = mint_url.try_into()?;
111 let wallets = self.inner.get_wallets().await;
112
113 if let Some(wallet) = wallets.iter().find(|w| w.mint_url == cdk_mint_url) {
114 let ttl = ttl_secs.map(std::time::Duration::from_secs);
115 wallet.set_metadata_cache_ttl(ttl);
116 Ok(())
117 } else {
118 Err(FfiError::internal(format!(
119 "Mint not found: {}",
120 cdk_mint_url
121 )))
122 }
123 }
124
125 pub async fn set_metadata_cache_ttl_for_all_mints(&self, ttl_secs: Option<u64>) {
134 let wallets = self.inner.get_wallets().await;
135 let ttl = ttl_secs.map(std::time::Duration::from_secs);
136
137 for wallet in wallets.iter() {
138 wallet.set_metadata_cache_ttl(ttl);
139 }
140 }
141
142 pub async fn create_wallet(
144 &self,
145 mint_url: MintUrl,
146 unit: Option<CurrencyUnit>,
147 target_proof_count: Option<u32>,
148 ) -> Result<(), FfiError> {
149 let cdk_mint_url: cdk::mint_url::MintUrl = mint_url.try_into()?;
150
151 let config = target_proof_count.map(|count| {
152 cdk::wallet::wallet_repository::WalletConfig::new()
153 .with_target_proof_count(count as usize)
154 });
155
156 let unit_enum = unit.unwrap_or(CurrencyUnit::Sat);
157
158 self.inner
159 .create_wallet(cdk_mint_url, unit_enum.into(), config)
160 .await?;
161
162 Ok(())
163 }
164
165 pub async fn remove_wallet(
167 &self,
168 mint_url: MintUrl,
169 currency_unit: CurrencyUnit,
170 ) -> Result<(), FfiError> {
171 let cdk_mint_url: cdk::mint_url::MintUrl = mint_url
173 .try_into()
174 .map_err(|_| FfiError::internal("invalid mint url"))?; self.inner
178 .remove_wallet(cdk_mint_url, currency_unit.into())
179 .await
180 .map_err(|e| e.into()) }
182
183 pub async fn has_mint(&self, mint_url: MintUrl) -> bool {
185 if let Ok(cdk_mint_url) = mint_url.try_into() {
186 self.inner.has_mint(&cdk_mint_url).await
187 } else {
188 false
189 }
190 }
191
192 pub fn mint_backup_public_key(&self) -> Result<String, FfiError> {
194 let keys = self.inner.backup_keys()?;
195 Ok(keys.public_key().to_hex())
196 }
197
198 pub async fn backup_mints(
200 &self,
201 relays: Vec<String>,
202 options: BackupOptions,
203 ) -> Result<BackupResult, FfiError> {
204 let result = self.inner.backup_mints(relays, options.into()).await?;
205 Ok(result.into())
206 }
207
208 pub async fn restore_mints(
210 &self,
211 relays: Vec<String>,
212 add_mints: bool,
213 options: RestoreOptions,
214 ) -> Result<RestoreResult, FfiError> {
215 let result = self
216 .inner
217 .restore_mints(relays, add_mints, options.into())
218 .await?;
219 Ok(result.into())
220 }
221
222 pub async fn fetch_mint_backup(
224 &self,
225 relays: Vec<String>,
226 options: RestoreOptions,
227 ) -> Result<MintBackup, FfiError> {
228 let backup = self.inner.fetch_backup(relays, options.into()).await?;
229 Ok(backup.into())
230 }
231
232 pub async fn get_balances(&self) -> Result<HashMap<WalletKey, Amount>, FfiError> {
234 let balances = self.inner.get_balances().await?;
235 let mut balance_map = HashMap::new();
236 for (wallet_key, amount) in balances {
237 balance_map.insert(wallet_key.into(), amount.into());
238 }
239 Ok(balance_map)
240 }
241
242 pub async fn get_wallets(&self) -> Vec<Arc<crate::wallet::Wallet>> {
244 let wallets = self.inner.get_wallets().await;
245 wallets
246 .into_iter()
247 .map(|w| Arc::new(crate::wallet::Wallet::from_inner(Arc::new(w))))
248 .collect()
249 }
250
251 pub async fn get_wallet(
255 &self,
256 mint_url: MintUrl,
257 unit: CurrencyUnit,
258 ) -> Result<Arc<crate::wallet::Wallet>, FfiError> {
259 let cdk_mint_url: cdk::mint_url::MintUrl = mint_url.try_into()?;
260 let unit_cdk: cdk::nuts::CurrencyUnit = unit.into();
261 let wallet = self.inner.get_wallet(&cdk_mint_url, &unit_cdk).await?;
262 Ok(Arc::new(crate::wallet::Wallet::from_inner(Arc::new(
263 wallet,
264 ))))
265 }
266
267 pub async fn get_token_data(
269 &self,
270 token: Arc<crate::token::Token>,
271 ) -> Result<TokenData, FfiError> {
272 Ok(self.inner.get_token_data(&token.inner).await?.into())
273 }
274}
275
276#[derive(Debug, Clone, uniffi::Record)]
280pub struct TokenData {
281 pub mint_url: MintUrl,
283 pub proofs: Vec<crate::types::Proof>,
285 pub memo: Option<String>,
287 pub value: Amount,
289 pub unit: CurrencyUnit,
291 pub redeem_fee: Option<Amount>,
293}
294
295impl From<cdk::wallet::TokenData> for TokenData {
296 fn from(data: cdk::wallet::TokenData) -> Self {
297 Self {
298 mint_url: data.mint_url.into(),
299 proofs: data.proofs.into_iter().map(Into::into).collect(),
300 memo: data.memo,
301 value: data.value.into(),
302 unit: data.unit.into(),
303 redeem_fee: data.redeem_fee.map(Into::into),
304 }
305 }
306}