1use std::cmp;
24use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
25use std::marker::PhantomData;
26use std::ops::{AddAssign, Deref};
27
28use bpstd::{
29 Address, AddressNetwork, DerivedAddr, Descriptor, Idx, IdxBase, Keychain, Network, NormalIndex,
30 Outpoint, Sats, ScriptPubkey, Txid, Vout,
31};
32use nonasync::persistence::{
33 CloneNoPersistence, Persistence, PersistenceError, PersistenceProvider, Persisting,
34};
35use psbt::{PsbtConstructor, Utxo};
36
37use crate::{
38 BlockInfo, CoinRow, Indexer, Layer2, Layer2Cache, Layer2Data, Layer2Descriptor, Layer2Empty,
39 MayError, MiningInfo, NoLayer2, Party, TxRow, WalletAddr, WalletTx, WalletUtxo,
40};
41
42#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
43#[display(doc_comments)]
44pub enum NonWalletItem {
45 NonWalletTx(Txid),
47 NoOutput(Txid, Vout),
49 NonWalletUtxo(Outpoint),
51}
52
53pub struct AddrIter<'descr, K, D: Descriptor<K>> {
54 generator: &'descr D,
55 network: AddressNetwork,
56 keychain: Keychain,
57 next_index: Option<NormalIndex>,
58 remaining: VecDeque<DerivedAddr>,
59 _phantom: PhantomData<K>,
60}
61
62impl<K, D: Descriptor<K>> Iterator for AddrIter<'_, K, D> {
63 type Item = DerivedAddr;
64
65 fn next(&mut self) -> Option<Self::Item> {
66 loop {
67 if let Some(derived) = self.remaining.pop_front() {
68 return Some(derived);
69 }
70 let current_index = self.next_index?;
71 self.remaining = self
72 .generator
73 .derive_address(self.network, self.keychain, current_index)
74 .map(|addr| DerivedAddr::new(addr, self.keychain, current_index))
75 .collect();
76 self.next_index.as_mut().map(|i| i.checked_inc_assign());
77 }
78 }
79}
80
81#[cfg_attr(
82 feature = "serde",
83 derive(serde::Serialize, serde::Deserialize),
84 serde(
85 crate = "serde_crate",
86 rename_all = "camelCase",
87 bound(
88 serialize = "D: serde::Serialize, L2: serde::Serialize",
89 deserialize = "D: serde::Deserialize<'de>, L2: serde::Deserialize<'de>"
90 )
91 )
92)]
93#[derive(Getters, Debug)]
94pub struct WalletDescr<K, D, L2 = Layer2Empty>
95where
96 D: Descriptor<K>,
97 L2: Layer2Descriptor,
98{
99 #[getter(skip)]
100 #[cfg_attr(feature = "serde", serde(skip))]
101 persistence: Option<Persistence<Self>>,
102
103 generator: D,
104 #[getter(as_copy)]
105 network: Network,
106 layer2: L2,
107 #[cfg_attr(feature = "serde", serde(skip))]
108 _phantom: PhantomData<K>,
109}
110
111impl<K, D: Descriptor<K>> WalletDescr<K, D, Layer2Empty> {
112 pub fn new_standard(descr: D, network: Network) -> Self {
113 WalletDescr {
114 persistence: None,
115 generator: descr,
116 network,
117 layer2: none!(),
118 _phantom: PhantomData,
119 }
120 }
121}
122
123impl<K, D: Descriptor<K>, L2: Layer2Descriptor> WalletDescr<K, D, L2> {
124 pub fn new_layer2(descr: D, layer2: L2, network: Network) -> Self {
125 WalletDescr {
126 persistence: None,
127 generator: descr,
128 network,
129 layer2,
130 _phantom: PhantomData,
131 }
132 }
133
134 pub fn addresses(&self, keychain: impl Into<Keychain>) -> AddrIter<K, D> {
135 AddrIter {
136 generator: &self.generator,
137 network: self.network.into(),
138 keychain: keychain.into(),
139 next_index: Some(NormalIndex::ZERO),
140 remaining: VecDeque::new(),
141 _phantom: PhantomData,
142 }
143 }
144
145 pub fn with_descriptor_mut<E>(
146 &mut self,
147 f: impl FnOnce(&mut D) -> Result<(), E>,
148 ) -> Result<(), E> {
149 f(&mut self.generator)?;
150 self.mark_dirty();
151 Ok(())
152 }
153}
154
155impl<K, D: Descriptor<K>, L2: Layer2Descriptor> Deref for WalletDescr<K, D, L2> {
156 type Target = D;
157
158 fn deref(&self) -> &Self::Target { &self.generator }
159}
160
161impl<K, D: Descriptor<K>, L2: Layer2Descriptor> CloneNoPersistence for WalletDescr<K, D, L2> {
162 fn clone_no_persistence(&self) -> Self {
163 Self {
164 persistence: None,
165 generator: self.generator.clone(),
166 network: self.network,
167 layer2: self.layer2.clone(),
168 _phantom: PhantomData,
169 }
170 }
171}
172
173impl<K, D: Descriptor<K>, L2: Layer2Descriptor> Persisting for WalletDescr<K, D, L2> {
174 #[inline]
175 fn persistence(&self) -> Option<&Persistence<Self>> { self.persistence.as_ref() }
176 #[inline]
177 fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>> { self.persistence.as_mut() }
178 #[inline]
179 fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>> { &mut self.persistence }
180}
181
182impl<K, D: Descriptor<K>, L2: Layer2Descriptor> Drop for WalletDescr<K, D, L2> {
183 fn drop(&mut self) {
184 if self.is_autosave() && self.is_dirty() {
185 if let Err(e) = self.store() {
186 #[cfg(feature = "log")]
187 log::error!("impossible to automatically-save wallet descriptor on Drop: {e}");
188 #[cfg(not(feature = "log"))]
189 eprintln!("impossible to automatically-save wallet descriptor on Drop: {e}")
190 }
191 }
192 }
193}
194
195#[derive(Debug)]
196#[cfg_attr(
197 feature = "serde",
198 derive(serde::Serialize, serde::Deserialize),
199 serde(
200 crate = "serde_crate",
201 rename_all = "camelCase",
202 bound(serialize = "L2: serde::Serialize", deserialize = "L2: serde::Deserialize<'de>")
203 )
204)]
205pub struct WalletData<L2: Layer2Data> {
206 #[cfg_attr(feature = "serde", serde(skip))]
207 persistence: Option<Persistence<Self>>,
208
209 #[cfg_attr(feature = "serde", serde(skip))]
211 pub id: Option<String>,
212 pub name: String,
213 pub tx_annotations: BTreeMap<Txid, String>,
214 pub txout_annotations: BTreeMap<Outpoint, String>,
215 pub txin_annotations: BTreeMap<Outpoint, String>,
216 pub addr_annotations: BTreeMap<Address, String>,
217 pub last_used: BTreeMap<Keychain, NormalIndex>,
218 pub layer2: L2,
219}
220
221impl<L2: Layer2Data> CloneNoPersistence for WalletData<L2> {
222 fn clone_no_persistence(&self) -> Self {
223 Self {
224 persistence: None,
225 id: self.id.clone(),
226 name: self.name.clone(),
227 tx_annotations: self.tx_annotations.clone(),
228 txout_annotations: self.txout_annotations.clone(),
229 txin_annotations: self.txin_annotations.clone(),
230 addr_annotations: self.addr_annotations.clone(),
231 layer2: self.layer2.clone(),
232 last_used: self.last_used.clone(),
233 }
234 }
235}
236
237impl<L2: Layer2Data> Persisting for WalletData<L2> {
238 #[inline]
239 fn persistence(&self) -> Option<&Persistence<Self>> { self.persistence.as_ref() }
240 #[inline]
241 fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>> { self.persistence.as_mut() }
242 #[inline]
243 fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>> { &mut self.persistence }
244}
245
246impl WalletData<Layer2Empty> {
247 pub fn new_layer1() -> Self {
248 WalletData {
249 persistence: None,
250 id: None,
251 name: none!(),
252 tx_annotations: empty!(),
253 txout_annotations: empty!(),
254 txin_annotations: empty!(),
255 addr_annotations: empty!(),
256 layer2: none!(),
257 last_used: empty!(),
258 }
259 }
260}
261
262impl<L2: Layer2Data> WalletData<L2> {
263 pub fn new_layer2() -> Self
264 where L2: Default {
265 WalletData {
266 persistence: None,
267 id: None,
268 name: none!(),
269 tx_annotations: empty!(),
270 txout_annotations: empty!(),
271 txin_annotations: empty!(),
272 addr_annotations: empty!(),
273 layer2: none!(),
274 last_used: empty!(),
275 }
276 }
277}
278
279impl<L2: Layer2Data> Drop for WalletData<L2> {
280 fn drop(&mut self) {
281 if self.is_autosave() && self.is_dirty() {
282 if let Err(e) = self.store() {
283 #[cfg(feature = "log")]
284 log::error!("impossible to automatically-save wallet data on Drop: {e}");
285 #[cfg(not(feature = "log"))]
286 eprintln!("impossible to automatically-save wallet data on Drop: {e}")
287 }
288 }
289 }
290}
291
292#[cfg_attr(
293 feature = "serde",
294 derive(serde::Serialize, serde::Deserialize),
295 serde(
296 crate = "serde_crate",
297 rename_all = "camelCase",
298 bound(serialize = "L2: serde::Serialize", deserialize = "L2: serde::Deserialize<'de>")
299 )
300)]
301#[derive(Debug)]
302pub struct WalletCache<L2: Layer2Cache> {
303 #[cfg_attr(feature = "serde", serde(skip))]
304 persistence: Option<Persistence<Self>>,
305
306 #[cfg_attr(feature = "serde", serde(skip))]
308 pub id: Option<String>,
309 pub last_block: MiningInfo,
310 pub last_change: NormalIndex,
311 pub headers: BTreeSet<BlockInfo>,
312 pub tx: BTreeMap<Txid, WalletTx>,
313 pub utxo: BTreeSet<Outpoint>,
314 pub addr: BTreeMap<Keychain, BTreeSet<WalletAddr>>,
315 pub layer2: L2,
316}
317
318impl<L2C: Layer2Cache> WalletCache<L2C> {
319 pub(crate) fn new_nonsync() -> Self {
320 WalletCache {
321 persistence: None,
322 id: None,
323 last_block: MiningInfo::genesis(),
324 last_change: NormalIndex::ZERO,
325 headers: none!(),
326 tx: none!(),
327 utxo: none!(),
328 addr: none!(),
329 layer2: none!(),
330 }
331 }
332
333 pub fn with<I: Indexer, K, D: Descriptor<K>, L2: Layer2<Cache = L2C>>(
334 descriptor: &WalletDescr<K, D, L2::Descr>,
335 indexer: &I,
336 ) -> MayError<Self, Vec<I::Error>> {
337 indexer.create::<K, D, L2>(descriptor)
338 }
339
340 pub fn update<I: Indexer, K, D: Descriptor<K>, L2: Layer2<Cache = L2C>>(
341 &mut self,
342 descriptor: &WalletDescr<K, D, L2::Descr>,
343 indexer: &I,
344 ) -> MayError<usize, Vec<I::Error>> {
345 let res = indexer.update::<K, D, L2>(descriptor, self);
346 self.mark_dirty();
347 res
348 }
349
350 pub fn sync_from_scratch<I: Indexer, K, D: Descriptor<K>, L2: Layer2<Cache = L2C>>(
351 &mut self,
352 descriptor: &WalletDescr<K, D, L2::Descr>,
353 indexer: &I,
354 ) -> MayError<(), Vec<I::Error>> {
355 let res = indexer.create::<K, D, L2>(descriptor);
356 let (ok, err) = res.split();
357 *self = ok;
358 self.mark_dirty();
359 MayError { ok: (), err }
360 }
361
362 pub fn addresses_on(&self, keychain: Keychain) -> &BTreeSet<WalletAddr> {
363 self.addr.get(&keychain).unwrap_or_else(|| {
364 panic!("keychain #{keychain} is not supported by the wallet descriptor")
365 })
366 }
367
368 pub fn has_outpoint(&self, outpoint: Outpoint) -> bool {
369 let Some(tx) = self.tx.get(&outpoint.txid) else {
370 return false;
371 };
372 let Some(out) = tx.outputs.get(outpoint.vout.to_usize()) else {
373 return false;
374 };
375 matches!(out.beneficiary, Party::Wallet(_))
376 }
377
378 #[inline]
379 pub fn is_unspent(&self, outpoint: Outpoint) -> bool { self.utxo.contains(&outpoint) }
380
381 pub fn outpoint_by(
382 &self,
383 outpoint: Outpoint,
384 ) -> Result<(WalletUtxo, ScriptPubkey), NonWalletItem> {
385 let tx = self.tx.get(&outpoint.txid).ok_or(NonWalletItem::NonWalletTx(outpoint.txid))?;
386 let debit = tx
387 .outputs
388 .get(outpoint.vout.into_usize())
389 .ok_or(NonWalletItem::NoOutput(outpoint.txid, outpoint.vout))?;
390 let terminal = debit.derived_addr().ok_or(NonWalletItem::NonWalletUtxo(outpoint))?.terminal;
391 let utxo = WalletUtxo {
393 outpoint,
394 value: debit.value,
395 terminal,
396 status: tx.status,
397 };
398 let spk =
399 debit.beneficiary.script_pubkey().ok_or(NonWalletItem::NonWalletUtxo(outpoint))?;
400 Ok((utxo, spk))
401 }
402
403 pub fn txos(&self) -> impl Iterator<Item = WalletUtxo> + '_ {
404 self.tx.iter().flat_map(|(txid, tx)| {
405 tx.outputs.iter().enumerate().filter_map(|(vout, out)| {
406 if let Party::Wallet(w) = out.beneficiary {
407 Some(WalletUtxo {
408 outpoint: Outpoint::new(*txid, vout as u32),
409 value: out.value,
410 terminal: w.terminal,
411 status: tx.status,
412 })
413 } else {
414 None
415 }
416 })
417 })
418 }
419
420 pub fn utxos(&self) -> impl Iterator<Item = WalletUtxo> + '_ {
421 self.utxo.iter().map(|outpoint| {
422 let tx = self.tx.get(&outpoint.txid).expect("cache data inconsistency");
423 let debit = tx.outputs.get(outpoint.vout_usize()).expect("cache data inconsistency");
424 let terminal =
425 debit.derived_addr().expect("UTXO doesn't belong to the wallet").terminal;
426 WalletUtxo {
428 outpoint: *outpoint,
429 value: debit.value,
430 terminal,
431 status: tx.status,
432 }
433 })
434 }
435}
436
437impl<L2: Layer2Cache> CloneNoPersistence for WalletCache<L2> {
438 fn clone_no_persistence(&self) -> Self {
439 Self {
440 persistence: None,
441 id: self.id.clone(),
442 last_block: self.last_block,
443 last_change: self.last_change,
444 headers: self.headers.clone(),
445 tx: self.tx.clone(),
446 utxo: self.utxo.clone(),
447 addr: self.addr.clone(),
448 layer2: self.layer2.clone(),
449 }
450 }
451}
452
453impl<L2: Layer2Cache> Persisting for WalletCache<L2> {
454 #[inline]
455 fn persistence(&self) -> Option<&Persistence<Self>> { self.persistence.as_ref() }
456 #[inline]
457 fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>> { self.persistence.as_mut() }
458 #[inline]
459 fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>> { &mut self.persistence }
460}
461
462impl<L2: Layer2Cache> Drop for WalletCache<L2> {
463 fn drop(&mut self) {
464 if self.is_autosave() && self.is_dirty() {
465 if let Err(e) = self.store() {
466 #[cfg(feature = "log")]
467 log::error!("impossible to automatically-save wallet cache on Drop: {e}");
468 #[cfg(not(feature = "log"))]
469 eprintln!("impossible to automatically-save wallet cache on Drop: {e}")
470 }
471 }
472 }
473}
474
475#[derive(Debug)]
476pub struct Wallet<K, D: Descriptor<K>, L2: Layer2 = NoLayer2> {
477 descr: WalletDescr<K, D, L2::Descr>,
478 data: WalletData<L2::Data>,
479 cache: WalletCache<L2::Cache>,
480 layer2: L2,
481}
482
483impl<K, D: Descriptor<K>, L2: Layer2> Deref for Wallet<K, D, L2> {
484 type Target = WalletDescr<K, D, L2::Descr>;
485
486 fn deref(&self) -> &Self::Target { &self.descr }
487}
488
489impl<K, D: Descriptor<K>, L2: Layer2> CloneNoPersistence for Wallet<K, D, L2> {
490 fn clone_no_persistence(&self) -> Self {
491 Self {
492 descr: self.descr.clone_no_persistence(),
493 data: self.data.clone_no_persistence(),
494 cache: self.cache.clone_no_persistence(),
495 layer2: self.layer2.clone_no_persistence(),
496 }
497 }
498}
499
500impl<K, D: Descriptor<K>, L2: Layer2> PsbtConstructor for Wallet<K, D, L2> {
501 type Key = K;
502 type Descr = D;
503
504 fn descriptor(&self) -> &D { &self.descr.generator }
505
506 fn utxo(&self, outpoint: Outpoint) -> Option<(Utxo, ScriptPubkey)> {
507 self.cache.outpoint_by(outpoint).ok().map(|(utxo, spk)| (utxo.into_utxo(), spk))
508 }
509
510 fn network(&self) -> Network { self.descr.network }
511
512 fn next_derivation_index(&mut self, keychain: impl Into<Keychain>, shift: bool) -> NormalIndex {
513 let keychain = keychain.into();
514 let mut idx = self.last_published_derivation_index(keychain);
515 let last_index = self.data.last_used.entry(keychain).or_default();
516 idx = cmp::max(*last_index, idx);
517 if shift {
518 *last_index = idx.saturating_add(1u32);
519 self.data.mark_dirty();
520 }
521 idx
522 }
523}
524
525impl<K, D: Descriptor<K>> Wallet<K, D> {
526 pub fn new_layer1(descr: D, network: Network) -> Self {
527 Wallet {
528 cache: WalletCache::new_nonsync(),
529 data: WalletData::new_layer1(),
530 descr: WalletDescr::new_standard(descr, network),
531 layer2: none!(),
532 }
533 }
534 pub fn data_l1(&self) -> &WalletData<Layer2Empty> { &self.data }
535 pub fn cache_l1(&self) -> &WalletCache<Layer2Empty> { &self.cache }
536}
537
538impl<K, D: Descriptor<K>, L2: Layer2> Wallet<K, D, L2> {
539 pub fn new_layer2(descr: D, l2_descr: L2::Descr, layer2: L2, network: Network) -> Self {
540 Wallet {
541 cache: WalletCache::new_nonsync(),
542 data: WalletData::new_layer2(),
543 descr: WalletDescr::new_layer2(descr, l2_descr, network),
544 layer2,
545 }
546 }
547
548 pub fn set_name(&mut self, name: String) {
549 self.data.name = name;
550 self.data.mark_dirty();
551 }
552
553 pub fn descriptor_mut<R>(
554 &mut self,
555 f: impl FnOnce(&mut WalletDescr<K, D, L2::Descr>) -> R,
556 ) -> R {
557 let res = f(&mut self.descr);
558 self.descr.mark_dirty();
559 res
560 }
561
562 pub fn data_l2(&self) -> &L2::Data { &self.data.layer2 }
563 pub fn cache_l2(&self) -> &L2::Cache { &self.cache.layer2 }
564
565 pub fn with_data_l2<R>(&mut self, f: impl FnOnce(&mut L2::Data) -> R) -> R {
566 let res = f(&mut self.data.layer2);
567 self.data.mark_dirty();
568 res
569 }
570 pub fn with_cache_l2<R>(&mut self, f: impl FnOnce(&mut L2::Cache) -> R) -> R {
571 let res = f(&mut self.cache.layer2);
572 self.cache.mark_dirty();
573 res
574 }
575
576 pub fn update<I: Indexer>(&mut self, indexer: &I) -> MayError<(), Vec<I::Error>> {
577 self.cache.update::<I, K, D, L2>(&self.descr, indexer).map(|_| ())
578 }
579
580 pub fn sync_from_scratch<I: Indexer>(&mut self, indexer: &I) -> MayError<(), Vec<I::Error>> {
581 self.cache.sync_from_scratch::<I, K, D, L2>(&self.descr, indexer).map(|_| ())
582 }
583
584 pub fn to_deriver(&self) -> D
585 where
586 D: Clone,
587 K: Clone,
588 {
589 self.descr.clone()
590 }
591
592 fn last_published_derivation_index(&self, keychain: impl Into<Keychain>) -> NormalIndex {
593 let keychain = keychain.into();
594 self.address_coins()
595 .keys()
596 .filter(|ad| ad.terminal.keychain == keychain)
597 .map(|ad| ad.terminal.index)
598 .max()
599 .as_ref()
600 .map(NormalIndex::saturating_inc)
601 .unwrap_or_default()
602 }
603
604 pub fn last_derivation_index(&self, keychain: impl Into<Keychain>) -> NormalIndex {
605 let keychain = keychain.into();
606 let last_index = self.data.last_used.get(&keychain).copied().unwrap_or_default();
607 cmp::max(last_index, self.last_published_derivation_index(keychain))
608 }
609
610 pub fn next_address(&mut self, keychain: impl Into<Keychain>, shift: bool) -> Address {
611 let keychain = keychain.into();
612 let index = self.next_derivation_index(keychain, shift);
613 self.addresses(keychain)
614 .nth(index.index() as usize)
615 .expect("address iterator always can produce address")
616 .addr
617 }
618
619 pub fn balance(&self) -> Sats { self.cache.coins().map(|utxo| utxo.amount).sum::<Sats>() }
620
621 #[inline]
622 pub fn transactions(&self) -> &BTreeMap<Txid, WalletTx> { &self.cache.tx }
623
624 #[inline]
625 pub fn coins(&self) -> impl Iterator<Item = CoinRow<<L2::Cache as Layer2Cache>::Coin>> + '_ {
626 self.cache.coins()
627 }
628
629 pub fn address_coins(
630 &self,
631 ) -> HashMap<DerivedAddr, Vec<CoinRow<<L2::Cache as Layer2Cache>::Coin>>> {
632 let map = HashMap::new();
633 self.coins().fold(map, |mut acc, txo| {
634 acc.entry(txo.address).or_default().push(txo);
635 acc
636 })
637 }
638
639 pub fn address_balance(&self) -> impl Iterator<Item = WalletAddr> + '_ {
640 self.cache.addr.values().flat_map(|set| set.iter()).copied()
641 }
642
643 #[inline]
644 pub fn history(&self) -> impl Iterator<Item = TxRow<<L2::Cache as Layer2Cache>::Tx>> + '_ {
645 self.cache.history()
646 }
647
648 pub fn has_outpoint(&self, outpoint: Outpoint) -> bool { self.cache.has_outpoint(outpoint) }
649 pub fn is_unspent(&self, outpoint: Outpoint) -> bool { self.cache.is_unspent(outpoint) }
650
651 pub fn outpoint_by(
652 &self,
653 outpoint: Outpoint,
654 ) -> Result<(WalletUtxo, ScriptPubkey), NonWalletItem> {
655 self.cache.outpoint_by(outpoint)
656 }
657
658 pub fn txos(&self) -> impl Iterator<Item = WalletUtxo> + '_ { self.cache.txos() }
659 pub fn utxos(&self) -> impl Iterator<Item = WalletUtxo> + '_ { self.cache.utxos() }
660
661 pub fn coinselect<'a>(
662 &'a self,
663 up_to: Sats,
664 selector: impl Fn(&WalletUtxo) -> bool + 'a,
665 ) -> impl Iterator<Item = Outpoint> + 'a {
666 let mut selected = Sats::ZERO;
667 self.utxos()
668 .filter(selector)
669 .take_while(move |utxo| {
670 if selected <= up_to {
671 selected.add_assign(utxo.value);
672 true
673 } else {
674 false
675 }
676 })
677 .map(|utxo| utxo.outpoint)
678 }
679}
680
681impl<K, D: Descriptor<K>, L2: Layer2> Wallet<K, D, L2> {
682 pub fn load<P>(provider: P, autosave: bool) -> Result<Wallet<K, D, L2>, PersistenceError>
683 where P: Clone
684 + PersistenceProvider<WalletDescr<K, D, L2::Descr>>
685 + PersistenceProvider<WalletData<L2::Data>>
686 + PersistenceProvider<WalletCache<L2::Cache>>
687 + PersistenceProvider<L2>
688 + 'static {
689 let descr = WalletDescr::<K, D, L2::Descr>::load(provider.clone(), autosave)?;
690 let data = WalletData::<L2::Data>::load(provider.clone(), autosave)?;
691 let cache = WalletCache::<L2::Cache>::load(provider.clone(), autosave)?;
692 let layer2 = L2::load(provider, autosave)?;
693
694 Ok(Wallet {
695 descr,
696 data,
697 cache,
698 layer2,
699 })
700 }
701
702 pub fn set_id(&mut self, id: &impl ToString) {
703 self.data.id = Some(id.to_string());
704 self.cache.id = Some(id.to_string());
705 }
706
707 pub fn make_persistent<P>(
708 &mut self,
709 provider: P,
710 autosave: bool,
711 ) -> Result<bool, PersistenceError>
712 where
713 P: Clone
714 + PersistenceProvider<WalletDescr<K, D, L2::Descr>>
715 + PersistenceProvider<WalletData<L2::Data>>
716 + PersistenceProvider<WalletCache<L2::Cache>>
717 + PersistenceProvider<L2>
718 + 'static,
719 {
720 let a = self.descr.make_persistent(provider.clone(), autosave)?;
721 let b = self.data.make_persistent(provider.clone(), autosave)?;
722 let c = self.cache.make_persistent(provider.clone(), autosave)?;
723 let d = self.layer2.make_persistent(provider, autosave)?;
724 Ok(a && b && c && d)
725 }
726
727 pub fn store(&mut self) -> Result<(), PersistenceError> {
728 self.descr.store()?;
731 self.data.store()?;
732 self.cache.store()?;
733 self.layer2.store()?;
734
735 Ok(())
736 }
737}