diff --git a/crates/cdk-cli/src/sub_commands/balance.rs b/crates/cdk-cli/src/sub_commands/balance.rs index 824e9821d..979532224 100644 --- a/crates/cdk-cli/src/sub_commands/balance.rs +++ b/crates/cdk-cli/src/sub_commands/balance.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use anyhow::Result; +use cdk::mint_url::MintUrl; use cdk::nuts::CurrencyUnit; -use cdk::url::UncheckedUrl; use cdk::wallet::multi_mint_wallet::MultiMintWallet; use cdk::Amount; @@ -14,8 +14,8 @@ pub async fn balance(multi_mint_wallet: &MultiMintWallet) -> Result<()> { pub async fn mint_balances( multi_mint_wallet: &MultiMintWallet, unit: &CurrencyUnit, -) -> Result> { - let wallets: HashMap = multi_mint_wallet.get_balances(unit).await?; +) -> Result> { + let wallets: HashMap = multi_mint_wallet.get_balances(unit).await?; let mut wallets_vec = Vec::with_capacity(wallets.capacity()); diff --git a/crates/cdk-cli/src/sub_commands/burn.rs b/crates/cdk-cli/src/sub_commands/burn.rs index a7194e966..b687a6205 100644 --- a/crates/cdk-cli/src/sub_commands/burn.rs +++ b/crates/cdk-cli/src/sub_commands/burn.rs @@ -1,16 +1,17 @@ use std::str::FromStr; use anyhow::Result; +use cdk::mint_url::MintUrl; use cdk::nuts::CurrencyUnit; use cdk::wallet::multi_mint_wallet::WalletKey; use cdk::wallet::MultiMintWallet; -use cdk::{Amount, UncheckedUrl}; +use cdk::Amount; use clap::Args; #[derive(Args)] pub struct BurnSubCommand { /// Mint Url - mint_url: Option, + mint_url: Option, /// Currency unit e.g. sat #[arg(default_value = "sat")] unit: String, diff --git a/crates/cdk-cli/src/sub_commands/mint.rs b/crates/cdk-cli/src/sub_commands/mint.rs index 57b31070d..d6cc73736 100644 --- a/crates/cdk-cli/src/sub_commands/mint.rs +++ b/crates/cdk-cli/src/sub_commands/mint.rs @@ -5,8 +5,8 @@ use std::time::Duration; use anyhow::Result; use cdk::amount::SplitTarget; use cdk::cdk_database::{Error, WalletDatabase}; +use cdk::mint_url::MintUrl; use cdk::nuts::{CurrencyUnit, MintQuoteState}; -use cdk::url::UncheckedUrl; use cdk::wallet::multi_mint_wallet::WalletKey; use cdk::wallet::{MultiMintWallet, Wallet}; use cdk::Amount; @@ -16,7 +16,7 @@ use tokio::time::sleep; #[derive(Args)] pub struct MintSubCommand { /// Mint url - mint_url: UncheckedUrl, + mint_url: MintUrl, /// Amount amount: u64, /// Currency unit e.g. sat diff --git a/crates/cdk-cli/src/sub_commands/mint_info.rs b/crates/cdk-cli/src/sub_commands/mint_info.rs index 5bcddc664..17804f2fd 100644 --- a/crates/cdk-cli/src/sub_commands/mint_info.rs +++ b/crates/cdk-cli/src/sub_commands/mint_info.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use cdk::url::UncheckedUrl; +use cdk::mint_url::MintUrl; use cdk::HttpClient; use clap::Args; use url::Url; @@ -7,7 +7,7 @@ use url::Url; #[derive(Args)] pub struct MintInfoSubcommand { /// Cashu Token - mint_url: UncheckedUrl, + mint_url: MintUrl, } pub async fn mint_info(proxy: Option, sub_command_args: &MintInfoSubcommand) -> Result<()> { diff --git a/crates/cdk-cli/src/sub_commands/restore.rs b/crates/cdk-cli/src/sub_commands/restore.rs index c9151df78..0cef42bfd 100644 --- a/crates/cdk-cli/src/sub_commands/restore.rs +++ b/crates/cdk-cli/src/sub_commands/restore.rs @@ -1,8 +1,8 @@ use std::str::FromStr; use anyhow::{anyhow, Result}; +use cdk::mint_url::MintUrl; use cdk::nuts::CurrencyUnit; -use cdk::url::UncheckedUrl; use cdk::wallet::multi_mint_wallet::WalletKey; use cdk::wallet::MultiMintWallet; use clap::Args; @@ -10,7 +10,7 @@ use clap::Args; #[derive(Args)] pub struct RestoreSubCommand { /// Mint Url - mint_url: UncheckedUrl, + mint_url: MintUrl, /// Currency unit e.g. sat #[arg(default_value = "sat")] unit: String, diff --git a/crates/cdk-cli/src/sub_commands/update_mint_url.rs b/crates/cdk-cli/src/sub_commands/update_mint_url.rs index 0a30063e4..6b4336c79 100644 --- a/crates/cdk-cli/src/sub_commands/update_mint_url.rs +++ b/crates/cdk-cli/src/sub_commands/update_mint_url.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, Result}; +use cdk::mint_url::MintUrl; use cdk::nuts::CurrencyUnit; -use cdk::url::UncheckedUrl; use cdk::wallet::multi_mint_wallet::WalletKey; use cdk::wallet::MultiMintWallet; use clap::Args; @@ -8,9 +8,9 @@ use clap::Args; #[derive(Args)] pub struct UpdateMintUrlSubCommand { /// Old Mint Url - old_mint_url: UncheckedUrl, + old_mint_url: MintUrl, /// New Mint Url - new_mint_url: UncheckedUrl, + new_mint_url: MintUrl, } pub async fn update_mint_url( diff --git a/crates/cdk-redb/src/error.rs b/crates/cdk-redb/src/error.rs index ca8bfbc3d..f9ad7ec11 100644 --- a/crates/cdk-redb/src/error.rs +++ b/crates/cdk-redb/src/error.rs @@ -34,6 +34,9 @@ pub enum Error { /// CDK Database Error #[error(transparent)] CDKDatabase(#[from] cdk::cdk_database::Error), + /// CDK Mint Url Error + #[error(transparent)] + CDKMintUrl(#[from] cdk::mint_url::Error), /// CDK Error #[error(transparent)] CDK(#[from] cdk::error::Error), diff --git a/crates/cdk-redb/src/migrations.rs b/crates/cdk-redb/src/migrations.rs index 7e34ccbd2..6a8fd8cf0 100644 --- a/crates/cdk-redb/src/migrations.rs +++ b/crates/cdk-redb/src/migrations.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; use std::sync::Arc; +use cdk::mint_url::MintUrl; use cdk::nuts::{CurrencyUnit, MeltQuoteState, MintQuoteState}; -use cdk::{Amount, UncheckedUrl}; +use cdk::Amount; use redb::{Database, ReadableTable, TableDefinition}; use serde::{Deserialize, Serialize}; @@ -15,7 +16,7 @@ const MELT_QUOTES_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mel #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct V0MintQuote { pub id: String, - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, pub amount: Amount, pub unit: CurrencyUnit, pub request: String, @@ -27,7 +28,7 @@ pub struct V0MintQuote { #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct V1MintQuote { pub id: String, - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, pub amount: Amount, pub unit: CurrencyUnit, pub request: String, diff --git a/crates/cdk-redb/src/mint/migrations.rs b/crates/cdk-redb/src/mint/migrations.rs index 7eae5e0e7..356712211 100644 --- a/crates/cdk-redb/src/mint/migrations.rs +++ b/crates/cdk-redb/src/mint/migrations.rs @@ -4,8 +4,9 @@ use std::str::FromStr; use std::sync::Arc; use cdk::mint::MintQuote; +use cdk::mint_url::MintUrl; use cdk::nuts::{CurrencyUnit, MintQuoteState, Proof, State}; -use cdk::{Amount, UncheckedUrl}; +use cdk::Amount; use lightning_invoice::Bolt11Invoice; use redb::{Database, ReadableTable, TableDefinition}; use serde::{Deserialize, Serialize}; @@ -26,11 +27,12 @@ pub fn migrate_02_to_03(db: Arc) -> Result { migrate_mint_proofs_02_to_03(db)?; Ok(3) } + /// Mint Quote Info #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] struct V1MintQuote { pub id: String, - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, pub amount: Amount, pub unit: CurrencyUnit, pub request: String, diff --git a/crates/cdk-redb/src/wallet/migrations.rs b/crates/cdk-redb/src/wallet/migrations.rs new file mode 100644 index 000000000..bbfbc24d6 --- /dev/null +++ b/crates/cdk-redb/src/wallet/migrations.rs @@ -0,0 +1,100 @@ +//! Wallet Migrations +use std::ops::Deref; +use std::str::FromStr; +use std::sync::Arc; + +use cdk::mint_url::MintUrl; +use redb::{ + Database, MultimapTableDefinition, ReadableMultimapTable, ReadableTable, TableDefinition, +}; + +use super::Error; + +// +const MINTS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mints_table"); +// +const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &[u8]> = + MultimapTableDefinition::new("mint_keysets"); + +pub fn migrate_01_to_02(db: Arc) -> Result { + migrate_trim_mint_urls_01_to_02(db)?; + Ok(2) +} + +fn migrate_mints_table_01_to_02(db: Arc) -> Result<(), Error> { + let mints: Vec<(String, String)>; + { + let read_txn = db.begin_read().map_err(Error::from)?; + let table = read_txn.open_table(MINTS_TABLE).map_err(Error::from)?; + + mints = table + .iter() + .map_err(Error::from)? + .flatten() + .map(|(mint_url, mint_info)| { + (mint_url.value().to_string(), mint_info.value().to_string()) + }) + .collect(); + } + + let write_txn = db.begin_write()?; + { + let mut table = write_txn.open_table(MINTS_TABLE).map_err(Error::from)?; + for (mint_url_str, info) in mints { + let mint_url = MintUrl::from_str(&mint_url_str).map_err(Error::from)?; + + table.remove(mint_url_str.as_str())?; + + table.insert(mint_url.to_string().as_str(), info.as_str())?; + } + } + write_txn.commit()?; + + Ok(()) +} + +fn migrate_mint_keyset_table_01_to_02(db: Arc) -> Result<(), Error> { + let mut mints: Vec<(String, Vec>)> = vec![]; + { + let read_txn = db.begin_read().map_err(Error::from)?; + let table = read_txn + .open_multimap_table(MINT_KEYSETS_TABLE) + .map_err(Error::from)?; + + let mint_keysets_range = table.iter().map_err(Error::from)?; + + for (url, keysets) in mint_keysets_range.flatten() { + let keysets: Vec> = keysets + .into_iter() + .flatten() + .map(|k| k.value().to_vec()) + .collect(); + + mints.push((url.value().to_string(), keysets)); + } + } + + let write_txn = db.begin_write()?; + { + let mut table = write_txn + .open_multimap_table(MINT_KEYSETS_TABLE) + .map_err(Error::from)?; + for (mint_url_str, keysets) in mints { + let mint_url = MintUrl::from_str(&mint_url_str).map_err(Error::from)?; + + table.remove_all(mint_url_str.as_str())?; + for keyset in keysets { + table.insert(mint_url.to_string().as_str(), keyset.deref())?; + } + } + } + write_txn.commit()?; + + Ok(()) +} + +fn migrate_trim_mint_urls_01_to_02(db: Arc) -> Result<(), Error> { + migrate_mints_table_01_to_02(Arc::clone(&db))?; + migrate_mint_keyset_table_01_to_02(Arc::clone(&db))?; + Ok(()) +} diff --git a/crates/cdk-redb/src/wallet/mod.rs b/crates/cdk-redb/src/wallet/mod.rs index d8706f712..c2858dc82 100644 --- a/crates/cdk-redb/src/wallet/mod.rs +++ b/crates/cdk-redb/src/wallet/mod.rs @@ -8,11 +8,11 @@ use std::sync::Arc; use async_trait::async_trait; use cdk::cdk_database::WalletDatabase; +use cdk::mint_url::MintUrl; use cdk::nuts::{ CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State, }; use cdk::types::ProofInfo; -use cdk::url::UncheckedUrl; use cdk::util::unix_time; use cdk::wallet::MintQuote; use cdk::{cdk_database, wallet}; @@ -22,7 +22,11 @@ use tracing::instrument; use super::error::Error; use crate::migrations::migrate_00_to_01; +use crate::wallet::migrations::migrate_01_to_02; +mod migrations; + +// const MINTS_TABLE: TableDefinition<&str, &str> = TableDefinition::new("mints_table"); // const MINT_KEYSETS_TABLE: MultimapTableDefinition<&str, &[u8]> = @@ -40,7 +44,7 @@ const CONFIG_TABLE: TableDefinition<&str, &str> = TableDefinition::new("config") const KEYSET_COUNTER: TableDefinition<&str, u32> = TableDefinition::new("keyset_counter"); const NOSTR_LAST_CHECKED: TableDefinition<&str, u32> = TableDefinition::new("keyset_counter"); -const DATABASE_VERSION: u32 = 1; +const DATABASE_VERSION: u32 = 2; /// Wallet Redb Database #[derive(Debug, Clone)] @@ -82,6 +86,10 @@ impl WalletRedbDatabase { current_file_version = migrate_00_to_01(Arc::clone(&db))?; } + if current_file_version == 1 { + current_file_version = migrate_01_to_02(Arc::clone(&db))?; + } + if current_file_version != DATABASE_VERSION { tracing::warn!( "Database upgrade did not complete at {} current is {}", @@ -90,6 +98,16 @@ impl WalletRedbDatabase { ); return Err(Error::UnknownDatabaseVersion); } + + let write_txn = db.begin_write()?; + { + let mut table = write_txn.open_table(CONFIG_TABLE)?; + + table + .insert("db_version", DATABASE_VERSION.to_string().as_str())?; + } + + write_txn.commit()?; } Ordering::Equal => { tracing::info!("Database is at current version {}", DATABASE_VERSION); @@ -142,7 +160,7 @@ impl WalletDatabase for WalletRedbDatabase { #[instrument(skip(self))] async fn add_mint( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, mint_info: Option, ) -> Result<(), Self::Err> { let db = self.db.lock().await; @@ -166,7 +184,7 @@ impl WalletDatabase for WalletRedbDatabase { } #[instrument(skip(self))] - async fn remove_mint(&self, mint_url: UncheckedUrl) -> Result<(), Self::Err> { + async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), Self::Err> { let db = self.db.lock().await; let write_txn = db.begin_write().map_err(Error::from)?; @@ -183,7 +201,7 @@ impl WalletDatabase for WalletRedbDatabase { } #[instrument(skip(self))] - async fn get_mint(&self, mint_url: UncheckedUrl) -> Result, Self::Err> { + async fn get_mint(&self, mint_url: MintUrl) -> Result, Self::Err> { let db = self.db.lock().await; let read_txn = db.begin_read().map_err(Into::::into)?; let table = read_txn.open_table(MINTS_TABLE).map_err(Error::from)?; @@ -199,7 +217,7 @@ impl WalletDatabase for WalletRedbDatabase { } #[instrument(skip(self))] - async fn get_mints(&self) -> Result>, Self::Err> { + async fn get_mints(&self) -> Result>, Self::Err> { let db = self.db.lock().await; let read_txn = db.begin_read().map_err(Error::from)?; let table = read_txn.open_table(MINTS_TABLE).map_err(Error::from)?; @@ -209,7 +227,7 @@ impl WalletDatabase for WalletRedbDatabase { .flatten() .map(|(mint, mint_info)| { ( - UncheckedUrl::from_str(mint.value()).unwrap(), + MintUrl::from_str(mint.value()).unwrap(), serde_json::from_str(mint_info.value()).ok(), ) }) @@ -221,8 +239,8 @@ impl WalletDatabase for WalletRedbDatabase { #[instrument(skip(self))] async fn update_mint_url( &self, - old_mint_url: UncheckedUrl, - new_mint_url: UncheckedUrl, + old_mint_url: MintUrl, + new_mint_url: MintUrl, ) -> Result<(), Self::Err> { // Update proofs table { @@ -275,7 +293,7 @@ impl WalletDatabase for WalletRedbDatabase { #[instrument(skip(self))] async fn add_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, keysets: Vec, ) -> Result<(), Self::Err> { let db = self.db.lock().await; @@ -314,7 +332,7 @@ impl WalletDatabase for WalletRedbDatabase { #[instrument(skip(self))] async fn get_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, ) -> Result>, Self::Err> { let db = self.db.lock().await; let read_txn = db.begin_read().map_err(Into::::into)?; @@ -576,7 +594,7 @@ impl WalletDatabase for WalletRedbDatabase { #[instrument(skip_all)] async fn get_proofs( &self, - mint_url: Option, + mint_url: Option, unit: Option, state: Option>, spending_conditions: Option>, diff --git a/crates/cdk-rexie/src/wallet.rs b/crates/cdk-rexie/src/wallet.rs index bbd842731..cf21e40b6 100644 --- a/crates/cdk-rexie/src/wallet.rs +++ b/crates/cdk-rexie/src/wallet.rs @@ -6,11 +6,11 @@ use std::result::Result; use async_trait::async_trait; use cdk::cdk_database::WalletDatabase; +use cdk::mint_url::MintUrl; use cdk::nuts::{ CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State, }; use cdk::types::ProofInfo; -use cdk::url::UncheckedUrl; use cdk::util::unix_time; use cdk::wallet::{MeltQuote, MintQuote}; use rexie::*; @@ -117,7 +117,7 @@ impl WalletDatabase for WalletRexieDatabase { async fn add_mint( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, mint_info: Option, ) -> Result<(), Self::Err> { let rexie = self.db.lock().await; @@ -141,7 +141,7 @@ impl WalletDatabase for WalletRexieDatabase { Ok(()) } - async fn remove_mint(&self, mint_url: UncheckedUrl) -> Result<(), Self::Err> { + async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), Self::Err> { let rexie = self.db.lock().await; let transaction = rexie @@ -159,7 +159,7 @@ impl WalletDatabase for WalletRexieDatabase { Ok(()) } - async fn get_mint(&self, mint_url: UncheckedUrl) -> Result, Self::Err> { + async fn get_mint(&self, mint_url: MintUrl) -> Result, Self::Err> { let rexie = self.db.lock().await; let transaction = rexie @@ -178,7 +178,7 @@ impl WalletDatabase for WalletRexieDatabase { Ok(mint_info) } - async fn get_mints(&self) -> Result>, Self::Err> { + async fn get_mints(&self) -> Result>, Self::Err> { let rexie = self.db.lock().await; let transaction = rexie @@ -192,7 +192,7 @@ impl WalletDatabase for WalletRexieDatabase { .await .map_err(Error::from)?; - let mints: HashMap> = mints + let mints: HashMap> = mints .into_iter() .map(|(url, info)| { ( @@ -207,8 +207,8 @@ impl WalletDatabase for WalletRexieDatabase { async fn update_mint_url( &self, - old_mint_url: UncheckedUrl, - new_mint_url: UncheckedUrl, + old_mint_url: MintUrl, + new_mint_url: MintUrl, ) -> Result<(), Self::Err> { let proofs = self .get_proofs(Some(old_mint_url), None, None, None) @@ -255,7 +255,7 @@ impl WalletDatabase for WalletRexieDatabase { async fn add_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, keysets: Vec, ) -> Result<(), Self::Err> { let rexie = self.db.lock().await; @@ -306,7 +306,7 @@ impl WalletDatabase for WalletRexieDatabase { async fn get_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, ) -> Result>, Self::Err> { let rexie = self.db.lock().await; @@ -593,7 +593,7 @@ impl WalletDatabase for WalletRexieDatabase { async fn get_proofs( &self, - mint_url: Option, + mint_url: Option, unit: Option, state: Option>, spending_conditions: Option>, diff --git a/crates/cdk-sqlite/src/mint/migrations/20240811031111_update_mint_url.sql b/crates/cdk-sqlite/src/mint/migrations/20240811031111_update_mint_url.sql new file mode 100644 index 000000000..db70cb1ec --- /dev/null +++ b/crates/cdk-sqlite/src/mint/migrations/20240811031111_update_mint_url.sql @@ -0,0 +1 @@ +UPDATE `mint_quote` SET `mint_url` = RTRIM(`mint_url`, '/'); diff --git a/crates/cdk-sqlite/src/wallet/migrations/20240810233905_update_mint_url.sql b/crates/cdk-sqlite/src/wallet/migrations/20240810233905_update_mint_url.sql new file mode 100644 index 000000000..be0e2d22a --- /dev/null +++ b/crates/cdk-sqlite/src/wallet/migrations/20240810233905_update_mint_url.sql @@ -0,0 +1,21 @@ +-- Delete duplicates from `mint` +DELETE FROM `mint` +WHERE `mint_url` IN ( + SELECT `mint_url` + FROM ( + SELECT RTRIM(`mint_url`, '/') AS trimmed_url, MIN(rowid) AS keep_id + FROM `mint` + GROUP BY trimmed_url + HAVING COUNT(*) > 1 + ) +) +AND rowid NOT IN ( + SELECT MIN(rowid) + FROM `mint` + GROUP BY RTRIM(`mint_url`, '/') +); + +UPDATE `mint` SET `mint_url` = RTRIM(`mint_url`, '/'); +UPDATE `keyset` SET `mint_url` = RTRIM(`mint_url`, '/'); +UPDATE `mint_quote` SET `mint_url` = RTRIM(`mint_url`, '/'); +UPDATE `proof` SET `mint_url` = RTRIM(`mint_url`, '/'); diff --git a/crates/cdk-sqlite/src/wallet/mod.rs b/crates/cdk-sqlite/src/wallet/mod.rs index 0441dcf07..21b35001d 100644 --- a/crates/cdk-sqlite/src/wallet/mod.rs +++ b/crates/cdk-sqlite/src/wallet/mod.rs @@ -7,13 +7,13 @@ use std::str::FromStr; use async_trait::async_trait; use cdk::amount::Amount; use cdk::cdk_database::{self, WalletDatabase}; +use cdk::mint_url::MintUrl; use cdk::nuts::{ CurrencyUnit, Id, KeySetInfo, Keys, MeltQuoteState, MintInfo, MintQuoteState, Proof, Proofs, PublicKey, SpendingConditions, State, }; use cdk::secret::Secret; use cdk::types::ProofInfo; -use cdk::url::UncheckedUrl; use cdk::wallet; use cdk::wallet::MintQuote; use error::Error; @@ -62,7 +62,7 @@ impl WalletDatabase for WalletSqliteDatabase { #[instrument(skip(self, mint_info))] async fn add_mint( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, mint_info: Option, ) -> Result<(), Self::Err> { let ( @@ -129,7 +129,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); } #[instrument(skip(self))] - async fn remove_mint(&self, mint_url: UncheckedUrl) -> Result<(), Self::Err> { + async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), Self::Err> { sqlx::query( r#" DELETE FROM mint @@ -145,7 +145,7 @@ WHERE mint_url=? } #[instrument(skip(self))] - async fn get_mint(&self, mint_url: UncheckedUrl) -> Result, Self::Err> { + async fn get_mint(&self, mint_url: MintUrl) -> Result, Self::Err> { let rec = sqlx::query( r#" SELECT * @@ -169,7 +169,7 @@ WHERE mint_url=?; } #[instrument(skip(self))] - async fn get_mints(&self) -> Result>, Self::Err> { + async fn get_mints(&self) -> Result>, Self::Err> { let rec = sqlx::query( r#" SELECT * @@ -197,8 +197,8 @@ FROM mint #[instrument(skip(self))] async fn update_mint_url( &self, - old_mint_url: UncheckedUrl, - new_mint_url: UncheckedUrl, + old_mint_url: MintUrl, + new_mint_url: MintUrl, ) -> Result<(), Self::Err> { let tables = ["mint_quote", "proof"]; for table in &tables { @@ -224,7 +224,7 @@ FROM mint #[instrument(skip(self, keysets))] async fn add_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, keysets: Vec, ) -> Result<(), Self::Err> { for keyset in keysets { @@ -251,7 +251,7 @@ VALUES (?, ?, ?, ?, ?); #[instrument(skip(self))] async fn get_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, ) -> Result>, Self::Err> { let recs = sqlx::query( r#" @@ -547,7 +547,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); #[instrument(skip(self, state, spending_conditions))] async fn get_proofs( &self, - mint_url: Option, + mint_url: Option, unit: Option, state: Option>, spending_conditions: Option>, diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index 879d5c216..d8df2afdd 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/crates/cdk/src/cdk_database/mod.rs @@ -14,6 +14,8 @@ use crate::mint; use crate::mint::MintKeySetInfo; #[cfg(feature = "mint")] use crate::mint::MintQuote as MintMintQuote; +#[cfg(feature = "wallet")] +use crate::mint_url::MintUrl; #[cfg(feature = "mint")] use crate::nuts::{BlindSignature, MeltQuoteState, MintQuoteState, Proof}; #[cfg(any(feature = "wallet", feature = "mint"))] @@ -23,8 +25,6 @@ use crate::nuts::{KeySetInfo, Keys, MintInfo, SpendingConditions}; #[cfg(feature = "wallet")] use crate::types::ProofInfo; #[cfg(feature = "wallet")] -use crate::url::UncheckedUrl; -#[cfg(feature = "wallet")] use crate::wallet; #[cfg(feature = "wallet")] use crate::wallet::MintQuote as WalletMintQuote; @@ -65,32 +65,32 @@ pub trait WalletDatabase: Debug { /// Add Mint to storage async fn add_mint( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, mint_info: Option, ) -> Result<(), Self::Err>; /// Remove Mint from storage - async fn remove_mint(&self, mint_url: UncheckedUrl) -> Result<(), Self::Err>; + async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), Self::Err>; /// Get mint from storage - async fn get_mint(&self, mint_url: UncheckedUrl) -> Result, Self::Err>; + async fn get_mint(&self, mint_url: MintUrl) -> Result, Self::Err>; /// Get all mints from storage - async fn get_mints(&self) -> Result>, Self::Err>; + async fn get_mints(&self) -> Result>, Self::Err>; /// Update mint url async fn update_mint_url( &self, - old_mint_url: UncheckedUrl, - new_mint_url: UncheckedUrl, + old_mint_url: MintUrl, + new_mint_url: MintUrl, ) -> Result<(), Self::Err>; /// Add mint keyset to storage async fn add_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, keysets: Vec, ) -> Result<(), Self::Err>; /// Get mint keysets for mint url async fn get_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, ) -> Result>, Self::Err>; /// Get mint keyset by id async fn get_keyset_by_id(&self, keyset_id: &Id) -> Result, Self::Err>; @@ -123,7 +123,7 @@ pub trait WalletDatabase: Debug { /// Get proofs from storage async fn get_proofs( &self, - mint_url: Option, + mint_url: Option, unit: Option, state: Option>, spending_conditions: Option>, diff --git a/crates/cdk/src/cdk_database/wallet_memory.rs b/crates/cdk/src/cdk_database/wallet_memory.rs index 63e7b181b..546d8d812 100644 --- a/crates/cdk/src/cdk_database/wallet_memory.rs +++ b/crates/cdk/src/cdk_database/wallet_memory.rs @@ -8,11 +8,11 @@ use tokio::sync::RwLock; use super::WalletDatabase; use crate::cdk_database::Error; +use crate::mint_url::MintUrl; use crate::nuts::{ CurrencyUnit, Id, KeySetInfo, Keys, MintInfo, Proofs, PublicKey, SpendingConditions, State, }; use crate::types::ProofInfo; -use crate::url::UncheckedUrl; use crate::util::unix_time; use crate::wallet; use crate::wallet::types::MintQuote; @@ -20,8 +20,8 @@ use crate::wallet::types::MintQuote; /// Wallet in Memory Database #[derive(Default, Debug, Clone)] pub struct WalletMemoryDatabase { - mints: Arc>>>, - mint_keysets: Arc>>>, + mints: Arc>>>, + mint_keysets: Arc>>>, keysets: Arc>>, mint_quotes: Arc>>, melt_quotes: Arc>>, @@ -67,32 +67,32 @@ impl WalletDatabase for WalletMemoryDatabase { async fn add_mint( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, mint_info: Option, ) -> Result<(), Self::Err> { self.mints.write().await.insert(mint_url, mint_info); Ok(()) } - async fn remove_mint(&self, mint_url: UncheckedUrl) -> Result<(), Self::Err> { + async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), Self::Err> { let mut mints = self.mints.write().await; mints.remove(&mint_url); Ok(()) } - async fn get_mint(&self, mint_url: UncheckedUrl) -> Result, Self::Err> { + async fn get_mint(&self, mint_url: MintUrl) -> Result, Self::Err> { Ok(self.mints.read().await.get(&mint_url).cloned().flatten()) } - async fn get_mints(&self) -> Result>, Error> { + async fn get_mints(&self) -> Result>, Error> { Ok(self.mints.read().await.clone()) } async fn update_mint_url( &self, - old_mint_url: UncheckedUrl, - new_mint_url: UncheckedUrl, + old_mint_url: MintUrl, + new_mint_url: MintUrl, ) -> Result<(), Self::Err> { let proofs = self .get_proofs(Some(old_mint_url), None, None, None) @@ -140,7 +140,7 @@ impl WalletDatabase for WalletMemoryDatabase { async fn add_mint_keysets( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, keysets: Vec, ) -> Result<(), Error> { let mut current_mint_keysets = self.mint_keysets.write().await; @@ -160,10 +160,7 @@ impl WalletDatabase for WalletMemoryDatabase { Ok(()) } - async fn get_mint_keysets( - &self, - mint_url: UncheckedUrl, - ) -> Result>, Error> { + async fn get_mint_keysets(&self, mint_url: MintUrl) -> Result>, Error> { match self.mint_keysets.read().await.get(&mint_url) { Some(keyset_ids) => { let mut keysets = vec![]; @@ -253,7 +250,7 @@ impl WalletDatabase for WalletMemoryDatabase { async fn get_proofs( &self, - mint_url: Option, + mint_url: Option, unit: Option, state: Option>, spending_conditions: Option>, diff --git a/crates/cdk/src/lib.rs b/crates/cdk/src/lib.rs index 574f41848..df74ead8b 100644 --- a/crates/cdk/src/lib.rs +++ b/crates/cdk/src/lib.rs @@ -12,10 +12,10 @@ pub mod dhke; pub mod error; #[cfg(feature = "mint")] pub mod mint; +pub mod mint_url; pub mod nuts; pub mod secret; pub mod types; -pub mod url; pub mod util; #[cfg(feature = "wallet")] pub mod wallet; @@ -34,8 +34,6 @@ pub use wallet::Wallet; #[doc(hidden)] pub use self::amount::Amount; #[doc(hidden)] -pub use self::url::UncheckedUrl; -#[doc(hidden)] pub use self::util::SECP256K1; #[cfg(feature = "wallet")] #[doc(hidden)] diff --git a/crates/cdk/src/mint/mod.rs b/crates/cdk/src/mint/mod.rs index 7f784c91a..ee1a6f0c4 100644 --- a/crates/cdk/src/mint/mod.rs +++ b/crates/cdk/src/mint/mod.rs @@ -14,9 +14,9 @@ use self::nut05::QuoteState; use self::nut11::EnforceSigFlag; use crate::cdk_database::{self, MintDatabase}; use crate::dhke::{hash_to_curve, sign_message, verify_message}; +use crate::mint_url::MintUrl; use crate::nuts::nut11::enforce_sig_flag; use crate::nuts::*; -use crate::url::UncheckedUrl; use crate::util::unix_time; use crate::Amount; @@ -29,7 +29,7 @@ pub use types::{MeltQuote, MintQuote}; #[derive(Clone)] pub struct Mint { /// Mint Url - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, /// Mint Info pub mint_info: MintInfo, /// Mint Storage backend @@ -154,7 +154,7 @@ impl Mint { } } - let mint_url = UncheckedUrl::from(mint_url); + let mint_url = MintUrl::from(mint_url); Ok(Self { mint_url, @@ -168,13 +168,13 @@ impl Mint { /// Set Mint Url #[instrument(skip_all)] - pub fn set_mint_url(&mut self, mint_url: UncheckedUrl) { + pub fn set_mint_url(&mut self, mint_url: MintUrl) { self.mint_url = mint_url; } /// Get Mint Url #[instrument(skip_all)] - pub fn get_mint_url(&self) -> &UncheckedUrl { + pub fn get_mint_url(&self) -> &MintUrl { &self.mint_url } @@ -194,7 +194,7 @@ impl Mint { #[instrument(skip_all)] pub async fn new_mint_quote( &self, - mint_url: UncheckedUrl, + mint_url: MintUrl, request: String, unit: CurrencyUnit, amount: Amount, diff --git a/crates/cdk/src/mint/types.rs b/crates/cdk/src/mint/types.rs index 233856620..44047fd9b 100644 --- a/crates/cdk/src/mint/types.rs +++ b/crates/cdk/src/mint/types.rs @@ -4,8 +4,9 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::CurrencyUnit; +use crate::mint_url::MintUrl; use crate::nuts::{MeltQuoteState, MintQuoteState}; -use crate::{Amount, UncheckedUrl}; +use crate::Amount; /// Mint Quote Info #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] @@ -13,7 +14,7 @@ pub struct MintQuote { /// Quote id pub id: String, /// Mint Url - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, /// Amount of quote pub amount: Amount, /// Unit of quote @@ -31,7 +32,7 @@ pub struct MintQuote { impl MintQuote { /// Create new [`MintQuote`] pub fn new( - mint_url: UncheckedUrl, + mint_url: MintUrl, request: String, unit: CurrencyUnit, amount: Amount, diff --git a/crates/cdk/src/mint_url.rs b/crates/cdk/src/mint_url.rs new file mode 100644 index 000000000..0c25e7e39 --- /dev/null +++ b/crates/cdk/src/mint_url.rs @@ -0,0 +1,120 @@ +// Copyright (c) 2022-2023 Yuki Kishimoto +// Distributed under the MIT software license + +//! Url + +use core::fmt; +use core::str::FromStr; + +use serde::{Deserialize, Deserializer, Serialize}; +use thiserror::Error; +use url::{ParseError, Url}; + +/// Url Error +#[derive(Debug, Error, PartialEq, Eq)] +pub enum Error { + /// Url error + #[error(transparent)] + Url(#[from] ParseError), +} + +/// MintUrl Url +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] +pub struct MintUrl(String); + +impl MintUrl { + /// New mint url + pub fn new(url: S) -> Self + where + S: Into, + { + let url: String = url.into(); + Self(url.trim_end_matches('/').to_string()) + } + + /// Empty mint url + pub fn empty() -> Self { + Self(String::new()) + } + + /// Join onto url + pub fn join(&self, path: &str) -> Result { + let url: Url = self.try_into()?; + Ok(url.join(path)?) + } + + /// Remove trailing slashes from url + pub fn trim_trailing_slashes(&self) -> Self { + Self(self.to_string().trim_end_matches('/').to_string()) + } +} +impl<'de> Deserialize<'de> for MintUrl { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + MintUrl::from_str(&s).map_err(serde::de::Error::custom) + } +} +impl From for MintUrl +where + S: Into, +{ + fn from(url: S) -> Self { + let url: String = url.into(); + Self(url.trim_end_matches('/').to_string()) + } +} + +impl FromStr for MintUrl { + type Err = Error; + + fn from_str(url: &str) -> Result { + Ok(Self::from(url)) + } +} + +impl TryFrom for Url { + type Error = Error; + + fn try_from(mint_url: MintUrl) -> Result { + Ok(Self::parse(&mint_url.0)?) + } +} + +impl TryFrom<&MintUrl> for Url { + type Error = Error; + + fn try_from(mint_url: &MintUrl) -> Result { + Ok(Self::parse(mint_url.0.as_str())?) + } +} + +impl fmt::Display for MintUrl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_trim_trailing_slashes() { + let very_unformatted_url = "http://url-to-check.com////"; + let unformatted_url = "http://url-to-check.com/"; + let formatted_url = "http://url-to-check.com"; + + let very_trimmed_url = MintUrl::from_str(very_unformatted_url).unwrap(); + assert_eq!("http://url-to-check.com", very_trimmed_url.to_string()); + + let trimmed_url = MintUrl::from_str(unformatted_url).unwrap(); + assert_eq!("http://url-to-check.com", trimmed_url.to_string()); + + let unchanged_url = MintUrl::from_str(formatted_url).unwrap(); + assert_eq!("http://url-to-check.com", unchanged_url.to_string()); + } +} diff --git a/crates/cdk/src/nuts/nut00/token.rs b/crates/cdk/src/nuts/nut00/token.rs index 9dc3864c0..3406e5af5 100644 --- a/crates/cdk/src/nuts/nut00/token.rs +++ b/crates/cdk/src/nuts/nut00/token.rs @@ -12,8 +12,8 @@ use serde::{Deserialize, Serialize}; use url::Url; use super::{Error, Proof, ProofV4, Proofs}; +use crate::mint_url::MintUrl; use crate::nuts::{CurrencyUnit, Id}; -use crate::url::UncheckedUrl; use crate::Amount; /// Token Enum @@ -40,7 +40,7 @@ impl fmt::Display for Token { impl Token { /// Create new [`Token`] pub fn new( - mint_url: UncheckedUrl, + mint_url: MintUrl, proofs: Proofs, memo: Option, unit: Option, @@ -66,7 +66,7 @@ impl Token { } /// Proofs in [`Token`] - pub fn proofs(&self) -> HashMap { + pub fn proofs(&self) -> HashMap { match self { Self::TokenV3(token) => token.proofs(), Self::TokenV4(token) => token.proofs(), @@ -140,14 +140,14 @@ impl FromStr for Token { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct TokenV3Token { /// Url of mint - pub mint: UncheckedUrl, + pub mint: MintUrl, /// [`Proofs`] pub proofs: Proofs, } impl TokenV3Token { /// Create new [`TokenV3Token`] - pub fn new(mint_url: UncheckedUrl, proofs: Proofs) -> Self { + pub fn new(mint_url: MintUrl, proofs: Proofs) -> Self { Self { mint: mint_url, proofs, @@ -171,7 +171,7 @@ pub struct TokenV3 { impl TokenV3 { /// Create new [`Token`] pub fn new( - mint_url: UncheckedUrl, + mint_url: MintUrl, proofs: Proofs, memo: Option, unit: Option, @@ -190,8 +190,8 @@ impl TokenV3 { }) } - fn proofs(&self) -> HashMap { - let mut proofs: HashMap = HashMap::new(); + fn proofs(&self) -> HashMap { + let mut proofs: HashMap = HashMap::new(); for token in self.token.clone() { let mint_url = token.mint; @@ -268,7 +268,7 @@ impl From for TokenV3 { pub struct TokenV4 { /// Mint Url #[serde(rename = "m")] - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, /// Token Unit #[serde(rename = "u", skip_serializing_if = "Option::is_none")] pub unit: Option, @@ -284,9 +284,9 @@ pub struct TokenV4 { impl TokenV4 { /// Proofs from token - pub fn proofs(&self) -> HashMap { + pub fn proofs(&self) -> HashMap { let mint_url = &self.mint_url; - let mut proofs: HashMap = HashMap::new(); + let mut proofs: HashMap = HashMap::new(); for token in self.token.clone() { let mut mint_proofs = token @@ -423,7 +423,7 @@ mod tests { use std::str::FromStr; use super::*; - use crate::UncheckedUrl; + use crate::mint_url::MintUrl; #[test] fn test_token_padding() { @@ -445,7 +445,7 @@ mod tests { assert_eq!( token.mint_url, - UncheckedUrl::from_str("http://localhost:3338").unwrap() + MintUrl::from_str("http://localhost:3338").unwrap() ); assert_eq!( token.token[0].keyset_id, @@ -500,7 +500,7 @@ mod tests { let token = TokenV3::from_str(token_str).unwrap(); assert_eq!( token.token[0].mint, - UncheckedUrl::from_str("https://8333.space:3338").unwrap() + MintUrl::from_str("https://8333.space:3338").unwrap() ); assert_eq!( token.token[0].proofs[0].clone().keyset_id, diff --git a/crates/cdk/src/types.rs b/crates/cdk/src/types.rs index dd6e4f488..01e9cae49 100644 --- a/crates/cdk/src/types.rs +++ b/crates/cdk/src/types.rs @@ -3,10 +3,10 @@ use serde::{Deserialize, Serialize}; use crate::error::Error; +use crate::mint_url::MintUrl; use crate::nuts::{ CurrencyUnit, MeltQuoteState, Proof, Proofs, PublicKey, SpendingConditions, State, }; -use crate::url::UncheckedUrl; /// Melt response with proofs #[derive(Debug, Clone, Hash, PartialEq, Eq, Default, Serialize, Deserialize)] @@ -27,7 +27,7 @@ pub struct ProofInfo { /// y pub y: PublicKey, /// Mint Url - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, /// Proof State pub state: State, /// Proof Spending Conditions @@ -40,7 +40,7 @@ impl ProofInfo { /// Create new [`ProofInfo`] pub fn new( proof: Proof, - mint_url: UncheckedUrl, + mint_url: MintUrl, state: State, unit: CurrencyUnit, ) -> Result { @@ -63,7 +63,7 @@ impl ProofInfo { /// Check if [`Proof`] matches conditions pub fn matches_conditions( &self, - mint_url: &Option, + mint_url: &Option, unit: &Option, state: &Option>, spending_conditions: &Option>, diff --git a/crates/cdk/src/url.rs b/crates/cdk/src/url.rs deleted file mode 100644 index 69032a74d..000000000 --- a/crates/cdk/src/url.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2022-2023 Yuki Kishimoto -// Distributed under the MIT software license - -//! Url - -use core::fmt; -use core::str::FromStr; - -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use url::{ParseError, Url}; - -/// Url Error -#[derive(Debug, Error, PartialEq, Eq)] -pub enum Error { - /// Url error - #[error(transparent)] - Url(#[from] ParseError), -} - -/// Unchecked Url -#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct UncheckedUrl(String); - -impl UncheckedUrl { - /// New unchecked url - pub fn new(url: S) -> Self - where - S: Into, - { - Self(url.into()) - } - - /// Empty unchecked url - pub fn empty() -> Self { - Self(String::new()) - } - - /// Join onto url - pub fn join(&self, path: &str) -> Result { - let url: Url = self.try_into()?; - Ok(url.join(path)?) - } -} - -impl From for UncheckedUrl -where - S: Into, -{ - fn from(url: S) -> Self { - Self(url.into()) - } -} - -impl FromStr for UncheckedUrl { - type Err = Error; - - fn from_str(url: &str) -> Result { - Ok(Self::from(url)) - } -} - -impl TryFrom for Url { - type Error = Error; - - fn try_from(unchecked_url: UncheckedUrl) -> Result { - Ok(Self::parse(&unchecked_url.0)?) - } -} - -impl TryFrom<&UncheckedUrl> for Url { - type Error = Error; - - fn try_from(unchecked_url: &UncheckedUrl) -> Result { - Ok(Self::parse(unchecked_url.0.as_str())?) - } -} - -impl fmt::Display for UncheckedUrl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_unchecked_relay_url() { - let relay = "wss://relay.damus.io:8333/"; - - let unchecked_relay_url = UncheckedUrl::from_str(relay).unwrap(); - - assert_eq!(relay, unchecked_relay_url.to_string()); - - // assert_eq!(relay, serde_json::to_string(&unchecked_relay_url).unwrap()); - - let relay = "wss://relay.damus.io:8333"; - - let unchecked_relay_url = UncheckedUrl::from_str(relay).unwrap(); - - assert_eq!(relay, unchecked_relay_url.to_string()); - - // assert_eq!(relay, - // serde_json::to_string(&unchecked_relay_url).unwrap()) - } -} diff --git a/crates/cdk/src/wallet/error.rs b/crates/cdk/src/wallet/error.rs index 0c479d4e1..e92e96412 100644 --- a/crates/cdk/src/wallet/error.rs +++ b/crates/cdk/src/wallet/error.rs @@ -89,7 +89,7 @@ pub enum Error { Cashu(#[from] crate::error::Error), /// Cashu Url Error #[error(transparent)] - CashuUrl(#[from] crate::url::Error), + CashuUrl(#[from] crate::mint_url::Error), /// Database Error #[error(transparent)] Database(#[from] crate::cdk_database::Error), diff --git a/crates/cdk/src/wallet/mod.rs b/crates/cdk/src/wallet/mod.rs index 78e7ad5db..4a954a973 100644 --- a/crates/cdk/src/wallet/mod.rs +++ b/crates/cdk/src/wallet/mod.rs @@ -17,6 +17,7 @@ use tracing::instrument; use crate::amount::SplitTarget; use crate::cdk_database::{self, WalletDatabase}; use crate::dhke::{construct_proofs, hash_to_curve}; +use crate::mint_url::MintUrl; use crate::nuts::nut00::token::Token; use crate::nuts::{ nut10, nut12, Conditions, CurrencyUnit, Id, KeySetInfo, Keys, Kind, MeltQuoteBolt11Response, @@ -25,7 +26,6 @@ use crate::nuts::{ State, SwapRequest, }; use crate::types::{Melted, ProofInfo}; -use crate::url::UncheckedUrl; use crate::util::{hex, unix_time}; use crate::{Amount, Bolt11Invoice, HttpClient, SECP256K1}; @@ -42,7 +42,7 @@ pub use types::{MeltQuote, MintQuote, SendKind}; #[derive(Debug, Clone)] pub struct Wallet { /// Mint Url - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, /// Unit pub unit: CurrencyUnit, /// Storage backend @@ -66,7 +66,7 @@ impl Wallet { .expect("Could not create master key"); Self { - mint_url: UncheckedUrl::from(mint_url), + mint_url: MintUrl::from(mint_url), unit, client: HttpClient::new(), localstore, @@ -176,7 +176,7 @@ impl Wallet { /// Update Mint information and related entries in the event a mint changes its URL #[instrument(skip(self))] - pub async fn update_mint_url(&mut self, new_mint_url: UncheckedUrl) -> Result<(), Error> { + pub async fn update_mint_url(&mut self, new_mint_url: MintUrl) -> Result<(), Error> { self.mint_url = new_mint_url.clone(); // Where the mint_url is in the database it must be updated self.localstore @@ -1506,7 +1506,7 @@ impl Wallet { p2pk_signing_keys: &[SecretKey], preimages: &[String], ) -> Result { - let mut received_proofs: HashMap = HashMap::new(); + let mut received_proofs: HashMap = HashMap::new(); let mint_url = &self.mint_url; // Add mint if it does not exist in the store if self diff --git a/crates/cdk/src/wallet/multi_mint_wallet.rs b/crates/cdk/src/wallet/multi_mint_wallet.rs index fd5d30c81..89fc75ee9 100644 --- a/crates/cdk/src/wallet/multi_mint_wallet.rs +++ b/crates/cdk/src/wallet/multi_mint_wallet.rs @@ -14,10 +14,11 @@ use tracing::instrument; use super::types::SendKind; use super::Error; use crate::amount::SplitTarget; +use crate::mint_url::MintUrl; use crate::nuts::{CurrencyUnit, SecretKey, SpendingConditions, Token}; use crate::types::Melted; use crate::wallet::types::MintQuote; -use crate::{Amount, UncheckedUrl, Wallet}; +use crate::{Amount, Wallet}; /// Multi Mint Wallet #[derive(Debug, Clone)] @@ -29,7 +30,7 @@ pub struct MultiMintWallet { /// Wallet Key #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct WalletKey { - mint_url: UncheckedUrl, + mint_url: MintUrl, unit: CurrencyUnit, } @@ -41,7 +42,7 @@ impl fmt::Display for WalletKey { impl WalletKey { /// Create new [`WalletKey`] - pub fn new(mint_url: UncheckedUrl, unit: CurrencyUnit) -> Self { + pub fn new(mint_url: MintUrl, unit: CurrencyUnit) -> Self { Self { mint_url, unit } } } @@ -102,7 +103,7 @@ impl MultiMintWallet { pub async fn get_balances( &self, unit: &CurrencyUnit, - ) -> Result, Error> { + ) -> Result, Error> { let mut balances = HashMap::new(); for (WalletKey { mint_url, unit: u }, wallet) in self.wallets.lock().await.iter() { diff --git a/crates/cdk/src/wallet/types.rs b/crates/cdk/src/wallet/types.rs index d78f2e11b..4cae6417e 100644 --- a/crates/cdk/src/wallet/types.rs +++ b/crates/cdk/src/wallet/types.rs @@ -2,8 +2,9 @@ use serde::{Deserialize, Serialize}; +use crate::mint_url::MintUrl; use crate::nuts::{CurrencyUnit, MeltQuoteState, MintQuoteState}; -use crate::{Amount, UncheckedUrl}; +use crate::Amount; /// Mint Quote Info #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] @@ -11,7 +12,7 @@ pub struct MintQuote { /// Quote id pub id: String, /// Mint Url - pub mint_url: UncheckedUrl, + pub mint_url: MintUrl, /// Amount of quote pub amount: Amount, /// Unit of quote