mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-23 07:35:03 +01:00
Simplify MintUrl, use it directly in wallet/client.rs
This commit is contained in:
@@ -6,7 +6,6 @@ use url::Url;
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MintInfoSubcommand {
|
||||
/// Cashu Token
|
||||
mint_url: MintUrl,
|
||||
}
|
||||
|
||||
@@ -17,7 +16,7 @@ pub async fn mint_info(proxy: Option<Url>, sub_command_args: &MintInfoSubcommand
|
||||
};
|
||||
|
||||
let info = client
|
||||
.get_mint_info(sub_command_args.mint_url.clone().try_into()?)
|
||||
.get_mint_info(sub_command_args.mint_url.clone())
|
||||
.await?;
|
||||
|
||||
println!("{:#?}", info);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use core::fmt;
|
||||
use core::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use url::{ParseError, Url};
|
||||
|
||||
@@ -22,7 +22,7 @@ pub enum Error {
|
||||
}
|
||||
|
||||
/// MintUrl Url
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct MintUrl(String);
|
||||
|
||||
impl MintUrl {
|
||||
@@ -60,25 +60,16 @@ impl MintUrl {
|
||||
Ok(formatted_url)
|
||||
}
|
||||
|
||||
/// Empty mint url
|
||||
pub fn empty() -> Self {
|
||||
Self(String::new())
|
||||
}
|
||||
|
||||
/// Join onto url
|
||||
pub fn join(&self, path: &str) -> Result<Url, Error> {
|
||||
let url: Url = self.try_into()?;
|
||||
Ok(url.join(path)?)
|
||||
Url::parse(&self.0)
|
||||
.and_then(|url| url.join(path))
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for MintUrl {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
MintUrl::from_str(&s).map_err(serde::de::Error::custom)
|
||||
/// Append path elements onto the URL
|
||||
pub fn join_paths(&self, path_elements: &[&str]) -> Result<Url, Error> {
|
||||
self.join(&path_elements.join("/"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,22 +85,6 @@ impl FromStr for MintUrl {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<MintUrl> for Url {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(mint_url: MintUrl) -> Result<Url, Self::Error> {
|
||||
Ok(Self::parse(&mint_url.0)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&MintUrl> for Url {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(mint_url: &MintUrl) -> Result<Url, Self::Error> {
|
||||
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)
|
||||
|
||||
@@ -66,9 +66,6 @@ pub enum Error {
|
||||
/// Unsupported token
|
||||
#[error("Unsupported payment method")]
|
||||
UnsupportedPaymentMethod,
|
||||
/// Invalid Url
|
||||
#[error("Invalid URL")]
|
||||
InvalidUrl,
|
||||
/// Serde Json error
|
||||
#[error(transparent)]
|
||||
SerdeJsonError(#[from] serde_json::Error),
|
||||
@@ -78,9 +75,6 @@ pub enum Error {
|
||||
/// Base64 error
|
||||
#[error(transparent)]
|
||||
Base64Error(#[from] bitcoin::base64::DecodeError),
|
||||
/// Parse Url Error
|
||||
#[error(transparent)]
|
||||
UrlParseError(#[from] url::ParseError),
|
||||
/// Ciborium error
|
||||
#[error(transparent)]
|
||||
CiboriumError(#[from] ciborium::de::Error<std::io::Error>),
|
||||
|
||||
@@ -9,7 +9,6 @@ use std::str::FromStr;
|
||||
use bitcoin::base64::engine::{general_purpose, GeneralPurpose};
|
||||
use bitcoin::base64::{alphabet, Engine as _};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
use super::{Error, Proof, ProofV4, Proofs};
|
||||
use crate::mint_url::MintUrl;
|
||||
@@ -181,9 +180,6 @@ impl TokenV3 {
|
||||
return Err(Error::ProofsRequired);
|
||||
}
|
||||
|
||||
// Check Url is valid
|
||||
let _: Url = (&mint_url).try_into().map_err(|_| Error::InvalidUrl)?;
|
||||
|
||||
Ok(Self {
|
||||
token: vec![TokenV3Token::new(mint_url, proofs)],
|
||||
memo,
|
||||
|
||||
@@ -7,6 +7,7 @@ use url::Url;
|
||||
|
||||
use super::Error;
|
||||
use crate::error::ErrorResponse;
|
||||
use crate::mint_url::MintUrl;
|
||||
use crate::nuts::nut15::Mpp;
|
||||
use crate::nuts::{
|
||||
BlindedMessage, CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysResponse,
|
||||
@@ -17,24 +18,6 @@ use crate::nuts::{
|
||||
};
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
|
||||
fn join_url(url: Url, paths: &[&str]) -> Result<Url, Error> {
|
||||
let mut url = url;
|
||||
for path in paths {
|
||||
if !url.path().ends_with('/') {
|
||||
url.path_segments_mut()
|
||||
.map_err(|_| Error::UrlPathSegments)?
|
||||
.push(path);
|
||||
} else {
|
||||
url.path_segments_mut()
|
||||
.map_err(|_| Error::UrlPathSegments)?
|
||||
.pop()
|
||||
.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
/// Http Client
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HttpClient {
|
||||
@@ -87,8 +70,8 @@ impl HttpClient {
|
||||
|
||||
/// Get Active Mint Keys [NUT-01]
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {
|
||||
let url = join_url(mint_url, &["v1", "keys"])?;
|
||||
pub async fn get_mint_keys(&self, mint_url: MintUrl) -> Result<Vec<KeySet>, Error> {
|
||||
let url = mint_url.join_paths(&["v1", "keys"])?;
|
||||
let keys = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
match serde_json::from_value::<KeysResponse>(keys.clone()) {
|
||||
@@ -99,8 +82,8 @@ impl HttpClient {
|
||||
|
||||
/// Get Keyset Keys [NUT-01]
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result<KeySet, Error> {
|
||||
let url = join_url(mint_url, &["v1", "keys", &keyset_id.to_string()])?;
|
||||
pub async fn get_mint_keyset(&self, mint_url: MintUrl, keyset_id: Id) -> Result<KeySet, Error> {
|
||||
let url = mint_url.join_paths(&["v1", "keys", &keyset_id.to_string()])?;
|
||||
let keys = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
match serde_json::from_value::<KeysResponse>(keys.clone()) {
|
||||
@@ -111,8 +94,8 @@ impl HttpClient {
|
||||
|
||||
/// Get Keysets [NUT-02]
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error> {
|
||||
let url = join_url(mint_url, &["v1", "keysets"])?;
|
||||
pub async fn get_mint_keysets(&self, mint_url: MintUrl) -> Result<KeysetResponse, Error> {
|
||||
let url = mint_url.join_paths(&["v1", "keysets"])?;
|
||||
let res = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
match serde_json::from_value::<KeysetResponse>(res.clone()) {
|
||||
@@ -125,12 +108,12 @@ impl HttpClient {
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn post_mint_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
amount: Amount,
|
||||
unit: CurrencyUnit,
|
||||
description: Option<String>,
|
||||
) -> Result<MintQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "mint", "quote", "bolt11"])?;
|
||||
let url = mint_url.join_paths(&["v1", "mint", "quote", "bolt11"])?;
|
||||
|
||||
let request = MintQuoteBolt11Request {
|
||||
amount,
|
||||
@@ -160,10 +143,10 @@ impl HttpClient {
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_mint_quote_status(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
quote_id: &str,
|
||||
) -> Result<MintQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "mint", "quote", "bolt11", quote_id])?;
|
||||
let url = mint_url.join_paths(&["v1", "mint", "quote", "bolt11", quote_id])?;
|
||||
|
||||
let res = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
@@ -180,11 +163,11 @@ impl HttpClient {
|
||||
#[instrument(skip(self, quote, premint_secrets), fields(mint_url = %mint_url))]
|
||||
pub async fn post_mint(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
quote: &str,
|
||||
premint_secrets: PreMintSecrets,
|
||||
) -> Result<MintBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "mint", "bolt11"])?;
|
||||
let url = mint_url.join_paths(&["v1", "mint", "bolt11"])?;
|
||||
|
||||
let request = MintBolt11Request {
|
||||
quote: quote.to_string(),
|
||||
@@ -210,12 +193,12 @@ impl HttpClient {
|
||||
#[instrument(skip(self, request), fields(mint_url = %mint_url))]
|
||||
pub async fn post_melt_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
unit: CurrencyUnit,
|
||||
request: Bolt11Invoice,
|
||||
mpp_amount: Option<Amount>,
|
||||
) -> Result<MeltQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11"])?;
|
||||
let url = mint_url.join_paths(&["v1", "melt", "quote", "bolt11"])?;
|
||||
|
||||
let options = mpp_amount.map(|amount| Mpp { amount });
|
||||
|
||||
@@ -244,10 +227,10 @@ impl HttpClient {
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_melt_quote_status(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
quote_id: &str,
|
||||
) -> Result<MeltQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11", quote_id])?;
|
||||
let url = mint_url.join_paths(&["v1", "melt", "quote", "bolt11", quote_id])?;
|
||||
|
||||
let res = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
@@ -262,12 +245,12 @@ impl HttpClient {
|
||||
#[instrument(skip(self, quote, inputs, outputs), fields(mint_url = %mint_url))]
|
||||
pub async fn post_melt(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
quote: String,
|
||||
inputs: Vec<Proof>,
|
||||
outputs: Option<Vec<BlindedMessage>>,
|
||||
) -> Result<MeltQuoteBolt11Response, Error> {
|
||||
let url = join_url(mint_url, &["v1", "melt", "bolt11"])?;
|
||||
let url = mint_url.join_paths(&["v1", "melt", "bolt11"])?;
|
||||
|
||||
let request = MeltBolt11Request {
|
||||
quote,
|
||||
@@ -299,10 +282,10 @@ impl HttpClient {
|
||||
#[instrument(skip(self, swap_request), fields(mint_url = %mint_url))]
|
||||
pub async fn post_swap(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
swap_request: SwapRequest,
|
||||
) -> Result<SwapResponse, Error> {
|
||||
let url = join_url(mint_url, &["v1", "swap"])?;
|
||||
let url = mint_url.join_paths(&["v1", "swap"])?;
|
||||
|
||||
let res = self
|
||||
.inner
|
||||
@@ -321,8 +304,8 @@ impl HttpClient {
|
||||
|
||||
/// Get Mint Info [NUT-06]
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn get_mint_info(&self, mint_url: Url) -> Result<MintInfo, Error> {
|
||||
let url = join_url(mint_url, &["v1", "info"])?;
|
||||
pub async fn get_mint_info(&self, mint_url: MintUrl) -> Result<MintInfo, Error> {
|
||||
let url = mint_url.join_paths(&["v1", "info"])?;
|
||||
|
||||
let res = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
@@ -339,10 +322,10 @@ impl HttpClient {
|
||||
#[instrument(skip(self), fields(mint_url = %mint_url))]
|
||||
pub async fn post_check_state(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
ys: Vec<PublicKey>,
|
||||
) -> Result<CheckStateResponse, Error> {
|
||||
let url = join_url(mint_url, &["v1", "checkstate"])?;
|
||||
let url = mint_url.join_paths(&["v1", "checkstate"])?;
|
||||
let request = CheckStateRequest { ys };
|
||||
|
||||
let res = self
|
||||
@@ -364,10 +347,10 @@ impl HttpClient {
|
||||
#[instrument(skip(self, request), fields(mint_url = %mint_url))]
|
||||
pub async fn post_restore(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
mint_url: MintUrl,
|
||||
request: RestoreRequest,
|
||||
) -> Result<RestoreResponse, Error> {
|
||||
let url = join_url(mint_url, &["v1", "restore"])?;
|
||||
let url = mint_url.join_paths(&["v1", "restore"])?;
|
||||
|
||||
let res = self
|
||||
.inner
|
||||
|
||||
@@ -18,7 +18,7 @@ impl Wallet {
|
||||
} else {
|
||||
let keys = self
|
||||
.client
|
||||
.get_mint_keyset(self.mint_url.clone().try_into()?, keyset_id)
|
||||
.get_mint_keyset(self.mint_url.clone(), keyset_id)
|
||||
.await?;
|
||||
|
||||
self.localstore.add_keys(keys.keys.clone()).await?;
|
||||
@@ -34,10 +34,7 @@ impl Wallet {
|
||||
/// Queries mint for all keysets
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_mint_keysets(&self) -> Result<Vec<KeySetInfo>, Error> {
|
||||
let keysets = self
|
||||
.client
|
||||
.get_mint_keysets(self.mint_url.clone().try_into()?)
|
||||
.await?;
|
||||
let keysets = self.client.get_mint_keysets(self.mint_url.clone()).await?;
|
||||
|
||||
self.localstore
|
||||
.add_mint_keysets(self.mint_url.clone(), keysets.keysets.clone())
|
||||
@@ -52,10 +49,7 @@ impl Wallet {
|
||||
/// keysets
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_active_mint_keyset(&self) -> Result<KeySetInfo, Error> {
|
||||
let keysets = self
|
||||
.client
|
||||
.get_mint_keysets(self.mint_url.clone().try_into()?)
|
||||
.await?;
|
||||
let keysets = self.client.get_mint_keysets(self.mint_url.clone()).await?;
|
||||
let keysets = keysets.keysets;
|
||||
|
||||
self.localstore
|
||||
|
||||
@@ -59,7 +59,7 @@ impl Wallet {
|
||||
|
||||
let quote_res = self
|
||||
.client
|
||||
.post_melt_quote(self.mint_url.clone().try_into()?, self.unit, invoice, mpp)
|
||||
.post_melt_quote(self.mint_url.clone(), self.unit, invoice, mpp)
|
||||
.await?;
|
||||
|
||||
if quote_res.amount != amount {
|
||||
@@ -90,7 +90,7 @@ impl Wallet {
|
||||
) -> Result<MeltQuoteBolt11Response, Error> {
|
||||
let response = self
|
||||
.client
|
||||
.get_melt_quote_status(self.mint_url.clone().try_into()?, quote_id)
|
||||
.get_melt_quote_status(self.mint_url.clone(), quote_id)
|
||||
.await?;
|
||||
|
||||
match self.localstore.get_melt_quote(quote_id).await? {
|
||||
@@ -149,7 +149,7 @@ impl Wallet {
|
||||
let melt_response = self
|
||||
.client
|
||||
.post_melt(
|
||||
self.mint_url.clone().try_into()?,
|
||||
self.mint_url.clone(),
|
||||
quote_id.to_string(),
|
||||
proofs.clone(),
|
||||
Some(premint_secrets.blinded_messages()),
|
||||
|
||||
@@ -67,7 +67,7 @@ impl Wallet {
|
||||
|
||||
let quote_res = self
|
||||
.client
|
||||
.post_mint_quote(mint_url.clone().try_into()?, amount, unit, description)
|
||||
.post_mint_quote(mint_url.clone(), amount, unit, description)
|
||||
.await?;
|
||||
|
||||
let quote = MintQuote {
|
||||
@@ -90,7 +90,7 @@ impl Wallet {
|
||||
pub async fn mint_quote_state(&self, quote_id: &str) -> Result<MintQuoteBolt11Response, Error> {
|
||||
let response = self
|
||||
.client
|
||||
.get_mint_quote_status(self.mint_url.clone().try_into()?, quote_id)
|
||||
.get_mint_quote_status(self.mint_url.clone(), quote_id)
|
||||
.await?;
|
||||
|
||||
match self.localstore.get_mint_quote(quote_id).await? {
|
||||
@@ -215,11 +215,7 @@ impl Wallet {
|
||||
|
||||
let mint_res = self
|
||||
.client
|
||||
.post_mint(
|
||||
self.mint_url.clone().try_into()?,
|
||||
quote_id,
|
||||
premint_secrets.clone(),
|
||||
)
|
||||
.post_mint(self.mint_url.clone(), quote_id, premint_secrets.clone())
|
||||
.await?;
|
||||
|
||||
let keys = self.get_keyset_keys(active_keyset_id).await?;
|
||||
|
||||
@@ -161,11 +161,7 @@ impl Wallet {
|
||||
/// Qeury mint for current mint information
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_mint_info(&self) -> Result<Option<MintInfo>, Error> {
|
||||
let mint_info = match self
|
||||
.client
|
||||
.get_mint_info(self.mint_url.clone().try_into()?)
|
||||
.await
|
||||
{
|
||||
let mint_info = match self.client.get_mint_info(self.mint_url.clone()).await {
|
||||
Ok(mint_info) => Some(mint_info),
|
||||
Err(err) => {
|
||||
tracing::warn!("Could not get mint info {}", err);
|
||||
@@ -281,7 +277,7 @@ impl Wallet {
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.post_restore(self.mint_url.clone().try_into()?, restore_request)
|
||||
.post_restore(self.mint_url.clone(), restore_request)
|
||||
.await?;
|
||||
|
||||
if response.signatures.is_empty() {
|
||||
|
||||
@@ -77,7 +77,7 @@ impl Wallet {
|
||||
|
||||
let spendable = self
|
||||
.client
|
||||
.post_check_state(self.mint_url.clone().try_into()?, proof_ys)
|
||||
.post_check_state(self.mint_url.clone(), proof_ys)
|
||||
.await?
|
||||
.states;
|
||||
|
||||
@@ -98,7 +98,7 @@ impl Wallet {
|
||||
pub async fn check_proofs_spent(&self, proofs: Proofs) -> Result<Vec<ProofState>, Error> {
|
||||
let spendable = self
|
||||
.client
|
||||
.post_check_state(self.mint_url.clone().try_into()?, proofs.ys()?)
|
||||
.post_check_state(self.mint_url.clone(), proofs.ys()?)
|
||||
.await?;
|
||||
let spent_ys: Vec<_> = spendable
|
||||
.states
|
||||
|
||||
@@ -34,10 +34,7 @@ impl Wallet {
|
||||
.await?
|
||||
.is_none()
|
||||
{
|
||||
tracing::debug!(
|
||||
"Mint not in localstore fetching info for: {}",
|
||||
self.mint_url
|
||||
);
|
||||
tracing::debug!("Mint not in localstore fetching info for: {mint_url}");
|
||||
self.get_mint_info().await?;
|
||||
}
|
||||
|
||||
@@ -134,7 +131,7 @@ impl Wallet {
|
||||
|
||||
let swap_response = self
|
||||
.client
|
||||
.post_swap(mint_url.clone().try_into()?, pre_swap.swap_request)
|
||||
.post_swap(mint_url.clone(), pre_swap.swap_request)
|
||||
.await?;
|
||||
|
||||
// Proof to keep
|
||||
|
||||
@@ -42,7 +42,7 @@ impl Wallet {
|
||||
|
||||
let swap_response = self
|
||||
.client
|
||||
.post_swap(mint_url.clone().try_into()?, pre_swap.swap_request)
|
||||
.post_swap(mint_url.clone(), pre_swap.swap_request)
|
||||
.await?;
|
||||
|
||||
let active_keyset_id = pre_swap.pre_mint_secrets.keyset_id;
|
||||
|
||||
Reference in New Issue
Block a user