fedimint_wallet_client/
client_db.rs

1use core::fmt;
2use std::ops;
3use std::str::FromStr;
4use std::time::SystemTime;
5
6use fedimint_client_module::module::init::recovery::RecoveryFromHistoryCommon;
7use fedimint_core::core::OperationId;
8use fedimint_core::encoding::{Decodable, Encodable};
9use fedimint_core::{TransactionId, impl_db_lookup, impl_db_record};
10use serde::{Deserialize, Serialize};
11use strum_macros::EnumIter;
12
13use crate::backup::WalletRecoveryState;
14
15#[derive(Clone, EnumIter, Debug)]
16pub enum DbKeyPrefix {
17    NextPegInTweakIndex = 0x2c,
18    PegInTweakIndex = 0x2d,
19    ClaimedPegIn = 0x2e,
20    RecoveryFinalized = 0x2f,
21    RecoveryState = 0x30,
22    SupportsSafeDeposit = 0x31,
23    /// Prefixes between 0xb0..=0xcf shall all be considered allocated for
24    /// historical and future external use
25    ExternalReservedStart = 0xb0,
26    /// Prefixes between 0xd0..=0xff shall all be considered allocated for
27    /// historical and future internal use
28    CoreInternalReservedStart = 0xd0,
29    /// Prefixes between 0xd0..=0xff shall all be considered allocated for
30    /// historical and future internal use
31    CoreInternalReservedEnd = 0xff,
32}
33
34impl std::fmt::Display for DbKeyPrefix {
35    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36        write!(f, "{self:?}")
37    }
38}
39
40/// An index of a deposit address
41///
42/// Under the hood it's similar to `ChildId`, but in a wallet module
43/// it's used often enough to deserve own newtype.
44#[derive(
45    Copy,
46    Clone,
47    Debug,
48    Encodable,
49    Decodable,
50    Serialize,
51    Deserialize,
52    Default,
53    PartialEq,
54    Eq,
55    PartialOrd,
56    Ord,
57)]
58pub struct TweakIdx(pub u64);
59
60impl fmt::Display for TweakIdx {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        f.write_fmt(format_args!("TweakIdx({})", self.0))
63    }
64}
65
66impl FromStr for TweakIdx {
67    type Err = <u64 as FromStr>::Err;
68
69    fn from_str(s: &str) -> Result<Self, Self::Err> {
70        Ok(Self(FromStr::from_str(s)?))
71    }
72}
73
74impl TweakIdx {
75    #[must_use]
76    pub fn next(self) -> Self {
77        Self(self.0 + 1)
78    }
79
80    #[must_use]
81    pub fn prev(self) -> Option<Self> {
82        self.0.checked_sub(1).map(Self)
83    }
84
85    #[must_use]
86    pub fn advance(self, i: u64) -> Self {
87        Self(self.0 + i)
88    }
89
90    pub fn saturating_sub(&self, rhs: TweakIdx) -> u64 {
91        self.0.saturating_sub(rhs.0)
92    }
93}
94
95impl ops::Sub for TweakIdx {
96    type Output = u64;
97
98    fn sub(self, rhs: Self) -> Self::Output {
99        self.0 - rhs.0
100    }
101}
102
103/// A counter tracking next index to use to derive a peg-in address
104#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
105pub struct NextPegInTweakIndexKey;
106
107impl_db_record!(
108    key = NextPegInTweakIndexKey,
109    value = TweakIdx,
110    db_prefix = DbKeyPrefix::NextPegInTweakIndex,
111);
112
113/// Peg in index that was already allocated and is being tracked for deposits to
114/// claim
115#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
116pub struct PegInTweakIndexKey(pub TweakIdx);
117
118#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
119pub struct PegInTweakIndexPrefix;
120
121#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
122pub struct PegInTweakIndexData {
123    /// [`OperationId`] corresponding to this peg-in address.
124    pub operation_id: OperationId,
125    /// Time the address was allocated (created)
126    pub creation_time: SystemTime,
127    /// Last time the client checked the address for pegins
128    pub last_check_time: Option<SystemTime>,
129    /// Next time client is going to checked the address for pegins
130    pub next_check_time: Option<SystemTime>,
131    /// All previous on chain outputs claimed for this peg-in address.
132    pub claimed: Vec<bitcoin::OutPoint>,
133}
134
135impl_db_record!(
136    key = PegInTweakIndexKey,
137    value = PegInTweakIndexData,
138    db_prefix = DbKeyPrefix::PegInTweakIndex,
139);
140
141impl_db_lookup!(
142    key = PegInTweakIndexKey,
143    query_prefix = PegInTweakIndexPrefix
144);
145
146#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
147pub struct ClaimedPegInKey {
148    pub peg_in_index: TweakIdx,
149    pub btc_out_point: bitcoin::OutPoint,
150}
151
152#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
153pub struct ClaimedPegInPrefix;
154
155#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
156pub struct ClaimedPegInData {
157    pub claim_txid: TransactionId,
158    pub change: Vec<fedimint_core::OutPoint>,
159}
160
161impl_db_record!(
162    key = ClaimedPegInKey,
163    value = ClaimedPegInData,
164    db_prefix = DbKeyPrefix::ClaimedPegIn,
165    notify_on_modify = true,
166);
167impl_db_lookup!(key = ClaimedPegInKey, query_prefix = ClaimedPegInPrefix);
168
169#[derive(Debug, Clone, Encodable, Decodable, Serialize)]
170pub struct RecoveryFinalizedKey;
171
172#[derive(Debug, Clone, Encodable, Decodable)]
173pub struct RecoveryFinalizedKeyPrefix;
174
175impl_db_record!(
176    key = RecoveryFinalizedKey,
177    value = bool,
178    db_prefix = DbKeyPrefix::RecoveryFinalized,
179);
180
181#[derive(Debug, Clone, Encodable, Decodable, Serialize)]
182pub struct RecoveryStateKey;
183
184#[derive(Debug, Clone, Encodable, Decodable)]
185pub struct RestoreStateKeyPrefix;
186
187impl_db_record!(
188    key = RecoveryStateKey,
189    value = (WalletRecoveryState, RecoveryFromHistoryCommon),
190    db_prefix = DbKeyPrefix::RecoveryState,
191);
192
193#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
194pub struct SupportsSafeDepositKey;
195
196#[derive(Clone, Debug, Encodable, Decodable)]
197pub struct SupportsSafeDepositPrefix;
198
199impl_db_record!(
200    key = SupportsSafeDepositKey,
201    value = (),
202    db_prefix = DbKeyPrefix::SupportsSafeDeposit,
203);
204
205impl_db_lookup!(
206    key = SupportsSafeDepositKey,
207    query_prefix = SupportsSafeDepositPrefix
208);