cdk_sqlite/wallet/
mod.rs

1//! SQLite Wallet Database
2
3use cdk_sql_common::SQLWalletDatabase;
4
5use crate::common::SqliteConnectionManager;
6
7pub mod memory;
8
9/// Mint SQLite implementation with rusqlite
10pub type WalletSqliteDatabase = SQLWalletDatabase<SqliteConnectionManager>;
11
12#[cfg(test)]
13mod tests {
14    use std::str::FromStr;
15
16    use cdk_common::database::WalletDatabase;
17    use cdk_common::nuts::{ProofDleq, State};
18    use cdk_common::secret::Secret;
19
20    use crate::WalletSqliteDatabase;
21
22    #[tokio::test]
23    #[cfg(feature = "sqlcipher")]
24    async fn test_sqlcipher() {
25        use cdk_common::mint_url::MintUrl;
26        use cdk_common::MintInfo;
27
28        use super::*;
29        let path = std::env::temp_dir()
30            .to_path_buf()
31            .join(format!("cdk-test-{}.sqlite", uuid::Uuid::new_v4()));
32        let db = WalletSqliteDatabase::new((path, "password".to_string()))
33            .await
34            .unwrap();
35
36        let mint_info = MintInfo::new().description("test");
37        let mint_url = MintUrl::from_str("https://mint.xyz").unwrap();
38
39        db.add_mint(mint_url.clone(), Some(mint_info.clone()))
40            .await
41            .unwrap();
42
43        let res = db.get_mint(mint_url).await.unwrap();
44        assert_eq!(mint_info, res.clone().unwrap());
45        assert_eq!("test", &res.unwrap().description.unwrap());
46    }
47
48    #[tokio::test]
49    async fn test_proof_with_dleq() {
50        use cdk_common::common::ProofInfo;
51        use cdk_common::mint_url::MintUrl;
52        use cdk_common::nuts::{CurrencyUnit, Id, Proof, PublicKey, SecretKey};
53        use cdk_common::Amount;
54
55        // Create a temporary database
56        let path = std::env::temp_dir()
57            .to_path_buf()
58            .join(format!("cdk-test-dleq-{}.sqlite", uuid::Uuid::new_v4()));
59
60        #[cfg(feature = "sqlcipher")]
61        let db = WalletSqliteDatabase::new((path, "password".to_string()))
62            .await
63            .unwrap();
64
65        #[cfg(not(feature = "sqlcipher"))]
66        let db = WalletSqliteDatabase::new(path).await.unwrap();
67
68        // Create a proof with DLEQ
69        let keyset_id = Id::from_str("00deadbeef123456").unwrap();
70        let mint_url = MintUrl::from_str("https://example.com").unwrap();
71        let secret = Secret::new("test_secret_for_dleq");
72
73        // Create DLEQ components
74        let e = SecretKey::generate();
75        let s = SecretKey::generate();
76        let r = SecretKey::generate();
77
78        let dleq = ProofDleq::new(e.clone(), s.clone(), r.clone());
79
80        let mut proof = Proof::new(
81            Amount::from(64),
82            keyset_id,
83            secret,
84            PublicKey::from_hex(
85                "02deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
86            )
87            .unwrap(),
88        );
89
90        // Add DLEQ to the proof
91        proof.dleq = Some(dleq);
92
93        // Create ProofInfo
94        let proof_info =
95            ProofInfo::new(proof, mint_url.clone(), State::Unspent, CurrencyUnit::Sat).unwrap();
96
97        // Store the proof in the database
98        db.update_proofs(vec![proof_info.clone()], vec![])
99            .await
100            .unwrap();
101
102        // Retrieve the proof from the database
103        let retrieved_proofs = db
104            .get_proofs(
105                Some(mint_url),
106                Some(CurrencyUnit::Sat),
107                Some(vec![State::Unspent]),
108                None,
109            )
110            .await
111            .unwrap();
112
113        // Verify we got back exactly one proof
114        assert_eq!(retrieved_proofs.len(), 1);
115
116        // Verify the DLEQ data was preserved
117        let retrieved_proof = &retrieved_proofs[0];
118        assert!(retrieved_proof.proof.dleq.is_some());
119
120        let retrieved_dleq = retrieved_proof.proof.dleq.as_ref().unwrap();
121
122        // Verify DLEQ components match what we stored
123        assert_eq!(retrieved_dleq.e.to_string(), e.to_string());
124        assert_eq!(retrieved_dleq.s.to_string(), s.to_string());
125        assert_eq!(retrieved_dleq.r.to_string(), r.to_string());
126    }
127
128    #[tokio::test]
129    async fn test_mint_quote_payment_method_read_and_write() {
130        use cdk_common::mint_url::MintUrl;
131        use cdk_common::nuts::{CurrencyUnit, MintQuoteState, PaymentMethod};
132        use cdk_common::wallet::MintQuote;
133        use cdk_common::Amount;
134
135        // Create a temporary database
136        let path = std::env::temp_dir().to_path_buf().join(format!(
137            "cdk-test-migration-{}.sqlite",
138            uuid::Uuid::new_v4()
139        ));
140
141        #[cfg(feature = "sqlcipher")]
142        let db = WalletSqliteDatabase::new((path, "password".to_string()))
143            .await
144            .unwrap();
145
146        #[cfg(not(feature = "sqlcipher"))]
147        let db = WalletSqliteDatabase::new(path).await.unwrap();
148
149        // Test PaymentMethod variants
150        let mint_url = MintUrl::from_str("https://example.com").unwrap();
151        let payment_methods = [
152            PaymentMethod::Bolt11,
153            PaymentMethod::Bolt12,
154            PaymentMethod::Custom("custom".to_string()),
155        ];
156
157        for (i, payment_method) in payment_methods.iter().enumerate() {
158            let quote = MintQuote {
159                id: format!("test_quote_{}", i),
160                mint_url: mint_url.clone(),
161                amount: Some(Amount::from(100)),
162                unit: CurrencyUnit::Sat,
163                request: "test_request".to_string(),
164                state: MintQuoteState::Unpaid,
165                expiry: 1000000000,
166                secret_key: None,
167                payment_method: payment_method.clone(),
168                amount_issued: Amount::from(0),
169                amount_paid: Amount::from(0),
170            };
171
172            // Store the quote
173            db.add_mint_quote(quote.clone()).await.unwrap();
174
175            // Retrieve and verify
176            let retrieved = db.get_mint_quote(&quote.id).await.unwrap().unwrap();
177            assert_eq!(retrieved.payment_method, *payment_method);
178            assert_eq!(retrieved.amount_issued, Amount::from(0));
179            assert_eq!(retrieved.amount_paid, Amount::from(0));
180        }
181    }
182}