mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-18 21:25:09 +01:00
compatibility for migrating Nutshell Mints quote ids (#984)
This commit is contained in:
@@ -44,4 +44,3 @@ uuid = { workspace = true, features = ["js"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bip39.workspace = true
|
||||
uuid.workspace = true
|
||||
|
||||
@@ -25,3 +25,107 @@ macro_rules! ensure_cdk {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
/// Quote ID. The specifications only define a string but CDK uses Uuid, so we use an enum to port compatibility.
|
||||
pub mod quote_id {
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use bitcoin::base64::engine::general_purpose;
|
||||
use bitcoin::base64::Engine as _;
|
||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Invalid UUID
|
||||
#[derive(Debug, Error)]
|
||||
pub enum QuoteIdError {
|
||||
/// UUID Error
|
||||
#[error("invalid UUID: {0}")]
|
||||
Uuid(#[from] uuid::Error),
|
||||
/// Invalid base64
|
||||
#[error("invalid base64")]
|
||||
Base64,
|
||||
/// Invalid quote ID
|
||||
#[error("neither a valid UUID nor a valid base64 string")]
|
||||
InvalidQuoteId,
|
||||
}
|
||||
|
||||
/// Mint Quote ID
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
|
||||
#[serde(untagged)]
|
||||
pub enum QuoteId {
|
||||
/// (Nutshell) base64 quote ID
|
||||
BASE64(String),
|
||||
/// UUID quote ID
|
||||
UUID(Uuid),
|
||||
}
|
||||
|
||||
impl QuoteId {
|
||||
/// Create a new UUID-based MintQuoteId
|
||||
pub fn new_uuid() -> Self {
|
||||
Self::UUID(Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for QuoteId {
|
||||
fn from(uuid: Uuid) -> Self {
|
||||
Self::UUID(uuid)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for QuoteId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
QuoteId::BASE64(s) => write!(f, "{}", s),
|
||||
QuoteId::UUID(u) => write!(f, "{}", u),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for QuoteId {
|
||||
type Err = QuoteIdError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// Try UUID first
|
||||
if let Ok(u) = Uuid::parse_str(s) {
|
||||
return Ok(QuoteId::UUID(u));
|
||||
}
|
||||
|
||||
// Try base64: decode, then re-encode and compare to ensure canonical form
|
||||
// Use the standard (URL/filename safe or standard) depending on your needed alphabet.
|
||||
// Here we use standard base64.
|
||||
match general_purpose::URL_SAFE.decode(s) {
|
||||
Ok(_bytes) => Ok(QuoteId::BASE64(s.to_string())),
|
||||
Err(_) => Err(QuoteIdError::InvalidQuoteId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for QuoteId {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// Deserialize as plain string first
|
||||
let s = String::deserialize(deserializer)?;
|
||||
|
||||
// Try UUID first
|
||||
if let Ok(u) = Uuid::parse_str(&s) {
|
||||
return Ok(QuoteId::UUID(u));
|
||||
}
|
||||
|
||||
if general_purpose::URL_SAFE.decode(&s).is_ok() {
|
||||
return Ok(QuoteId::BASE64(s));
|
||||
}
|
||||
|
||||
// Neither matched — return a helpful error
|
||||
Err(de::Error::custom(format!(
|
||||
"QuoteId must be either a UUID (e.g. {}) or a valid base64 string; got: {}",
|
||||
Uuid::nil(),
|
||||
s
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,12 @@ use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, Visitor};
|
||||
use serde::ser::{SerializeStruct, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::nut00::{BlindSignature, BlindedMessage, CurrencyUnit, PaymentMethod};
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::quote_id::QuoteId;
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::quote_id::QuoteIdError;
|
||||
use crate::Amount;
|
||||
|
||||
/// NUT04 Error
|
||||
@@ -44,12 +46,12 @@ pub struct MintRequest<Q> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl TryFrom<MintRequest<String>> for MintRequest<Uuid> {
|
||||
type Error = uuid::Error;
|
||||
impl TryFrom<MintRequest<String>> for MintRequest<QuoteId> {
|
||||
type Error = QuoteIdError;
|
||||
|
||||
fn try_from(value: MintRequest<String>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
quote: Uuid::from_str(&value.quote)?,
|
||||
quote: QuoteId::from_str(&value.quote)?,
|
||||
outputs: value.outputs,
|
||||
signature: value.signature,
|
||||
})
|
||||
|
||||
@@ -9,11 +9,11 @@ use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, Visitor};
|
||||
use serde::ser::{SerializeStruct, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::nut00::{BlindedMessage, CurrencyUnit, PaymentMethod, Proofs};
|
||||
use super::ProofsMethods;
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::quote_id::QuoteId;
|
||||
use crate::Amount;
|
||||
|
||||
/// NUT05 Error
|
||||
@@ -28,6 +28,9 @@ pub enum Error {
|
||||
/// Unsupported unit
|
||||
#[error("Unsupported unit")]
|
||||
UnsupportedUnit,
|
||||
/// Invalid quote id
|
||||
#[error("Invalid quote id")]
|
||||
InvalidQuote,
|
||||
}
|
||||
|
||||
/// Possible states of a quote
|
||||
@@ -91,12 +94,12 @@ pub struct MeltRequest<Q> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl TryFrom<MeltRequest<String>> for MeltRequest<Uuid> {
|
||||
type Error = uuid::Error;
|
||||
impl TryFrom<MeltRequest<String>> for MeltRequest<QuoteId> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: MeltRequest<String>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
quote: Uuid::from_str(&value.quote)?,
|
||||
quote: QuoteId::from_str(&value.quote).map_err(|_e| Error::InvalidQuote)?,
|
||||
inputs: value.inputs,
|
||||
outputs: value.outputs,
|
||||
})
|
||||
|
||||
@@ -1262,6 +1262,7 @@ impl<'de> Deserialize<'de> for Tag {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
@@ -1270,6 +1271,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::nuts::Id;
|
||||
use crate::quote_id::QuoteId;
|
||||
use crate::secret::Secret;
|
||||
use crate::{Amount, BlindedMessage};
|
||||
|
||||
@@ -1514,7 +1516,11 @@ mod tests {
|
||||
let blinded_msg = create_test_blinded_msg(pubkey);
|
||||
|
||||
// Create melt request
|
||||
let mut melt = MeltRequest::new(Uuid::new_v4(), vec![proof], Some(vec![blinded_msg]));
|
||||
let mut melt = MeltRequest::new(
|
||||
QuoteId::UUID(Uuid::new_v4()),
|
||||
vec![proof],
|
||||
Some(vec![blinded_msg]),
|
||||
);
|
||||
|
||||
// Before signing, should fail verification
|
||||
assert!(
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//! Specific Subscription for the cdk crate
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
use super::PublicKey;
|
||||
use crate::nuts::{
|
||||
CurrencyUnit, MeltQuoteBolt11Response, MintQuoteBolt11Response, PaymentMethod, ProofState,
|
||||
};
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::quote_id::{QuoteId, QuoteIdError};
|
||||
use crate::MintQuoteBolt12Response;
|
||||
|
||||
pub mod ws;
|
||||
@@ -154,14 +154,14 @@ impl<T> From<MintQuoteBolt11Response<T>> for NotificationPayload<T> {
|
||||
pub enum Notification {
|
||||
/// ProofState id is a Pubkey
|
||||
ProofState(PublicKey),
|
||||
/// MeltQuote id is an Uuid
|
||||
MeltQuoteBolt11(Uuid),
|
||||
/// MintQuote id is an Uuid
|
||||
MintQuoteBolt11(Uuid),
|
||||
/// MintQuote id is an Uuid
|
||||
MintQuoteBolt12(Uuid),
|
||||
/// MintQuote id is an Uuid
|
||||
MeltQuoteBolt12(Uuid),
|
||||
/// MeltQuote id is an QuoteId
|
||||
MeltQuoteBolt11(QuoteId),
|
||||
/// MintQuote id is an QuoteId
|
||||
MintQuoteBolt11(QuoteId),
|
||||
/// MintQuote id is an QuoteId
|
||||
MintQuoteBolt12(QuoteId),
|
||||
/// MintQuote id is an QuoteId
|
||||
MeltQuoteBolt12(QuoteId),
|
||||
}
|
||||
|
||||
/// Kind
|
||||
@@ -190,7 +190,7 @@ pub enum Error {
|
||||
#[cfg(feature = "mint")]
|
||||
#[error("Uuid Error: {0}")]
|
||||
/// Uuid Error
|
||||
Uuid(#[from] uuid::Error),
|
||||
QuoteId(#[from] QuoteIdError),
|
||||
|
||||
#[error("PublicKey Error: {0}")]
|
||||
/// PublicKey Error
|
||||
|
||||
@@ -74,8 +74,6 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@@ -111,8 +109,11 @@ mod tests {
|
||||
assert_eq!(expected_msg_to_sign, request_msg_to_sign);
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
#[test]
|
||||
fn test_valid_signature() {
|
||||
use uuid::Uuid;
|
||||
|
||||
let pubkey = PublicKey::from_hex(
|
||||
"03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac",
|
||||
)
|
||||
|
||||
@@ -8,10 +8,10 @@ use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{BlindSignature, CurrencyUnit, MeltQuoteState, Mpp, PublicKey};
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::quote_id::QuoteId;
|
||||
use crate::Amount;
|
||||
|
||||
/// NUT023 Error
|
||||
@@ -120,8 +120,8 @@ impl<Q: ToString> MintQuoteBolt11Response<Q> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl From<MintQuoteBolt11Response<Uuid>> for MintQuoteBolt11Response<String> {
|
||||
fn from(value: MintQuoteBolt11Response<Uuid>) -> Self {
|
||||
impl From<MintQuoteBolt11Response<QuoteId>> for MintQuoteBolt11Response<String> {
|
||||
fn from(value: MintQuoteBolt11Response<QuoteId>) -> Self {
|
||||
Self {
|
||||
quote: value.quote.to_string(),
|
||||
request: value.request,
|
||||
@@ -293,8 +293,8 @@ impl<Q: ToString> MeltQuoteBolt11Response<Q> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl From<MeltQuoteBolt11Response<Uuid>> for MeltQuoteBolt11Response<String> {
|
||||
fn from(value: MeltQuoteBolt11Response<Uuid>) -> Self {
|
||||
impl From<MeltQuoteBolt11Response<QuoteId>> for MeltQuoteBolt11Response<String> {
|
||||
fn from(value: MeltQuoteBolt11Response<QuoteId>) -> Self {
|
||||
Self {
|
||||
quote: value.quote.to_string(),
|
||||
amount: value.amount,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//! Bolt12
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{CurrencyUnit, MeltOptions, PublicKey};
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::quote_id::QuoteId;
|
||||
use crate::Amount;
|
||||
|
||||
/// NUT18 Error
|
||||
@@ -76,8 +76,8 @@ impl<Q: ToString> MintQuoteBolt12Response<Q> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl From<MintQuoteBolt12Response<Uuid>> for MintQuoteBolt12Response<String> {
|
||||
fn from(value: MintQuoteBolt12Response<Uuid>) -> Self {
|
||||
impl From<MintQuoteBolt12Response<QuoteId>> for MintQuoteBolt12Response<String> {
|
||||
fn from(value: MintQuoteBolt12Response<QuoteId>) -> Self {
|
||||
Self {
|
||||
quote: value.quote.to_string(),
|
||||
request: value.request,
|
||||
|
||||
@@ -3,6 +3,7 @@ use axum::extract::{Json, Path, State};
|
||||
use axum::response::Response;
|
||||
#[cfg(feature = "swagger")]
|
||||
use cdk::error::ErrorResponse;
|
||||
use cdk::mint::QuoteId;
|
||||
#[cfg(feature = "auth")]
|
||||
use cdk::nuts::nut21::{Method, ProtectedEndpoint, RoutePath};
|
||||
use cdk::nuts::{
|
||||
@@ -11,17 +12,16 @@ use cdk::nuts::{
|
||||
};
|
||||
use paste::paste;
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "auth")]
|
||||
use crate::auth::AuthHeader;
|
||||
use crate::{into_response, post_cache_wrapper, MintState};
|
||||
|
||||
post_cache_wrapper!(post_mint_bolt12, MintRequest<Uuid>, MintResponse);
|
||||
post_cache_wrapper!(post_mint_bolt12, MintRequest<QuoteId>, MintResponse);
|
||||
post_cache_wrapper!(
|
||||
post_melt_bolt12,
|
||||
MeltRequest<Uuid>,
|
||||
MeltQuoteBolt11Response<Uuid>
|
||||
MeltRequest<QuoteId>,
|
||||
MeltQuoteBolt11Response<QuoteId>
|
||||
);
|
||||
|
||||
#[cfg_attr(feature = "swagger", utoipa::path(
|
||||
@@ -38,7 +38,7 @@ pub async fn post_mint_bolt12_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MintQuoteBolt12Request>,
|
||||
) -> Result<Json<MintQuoteBolt12Response<Uuid>>, Response> {
|
||||
) -> Result<Json<MintQuoteBolt12Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
@@ -77,8 +77,8 @@ pub async fn post_mint_bolt12_quote(
|
||||
pub async fn get_check_mint_bolt12_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Path(quote_id): Path<Uuid>,
|
||||
) -> Result<Json<MintQuoteBolt12Response<Uuid>>, Response> {
|
||||
Path(quote_id): Path<QuoteId>,
|
||||
) -> Result<Json<MintQuoteBolt12Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
@@ -115,7 +115,7 @@ pub async fn get_check_mint_bolt12_quote(
|
||||
pub async fn post_mint_bolt12(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MintRequest<Uuid>>,
|
||||
Json(payload): Json<MintRequest<QuoteId>>,
|
||||
) -> Result<Json<MintResponse>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
@@ -155,7 +155,7 @@ pub async fn post_melt_bolt12_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MeltQuoteBolt12Request>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<Uuid>>, Response> {
|
||||
) -> Result<Json<MeltQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
@@ -193,8 +193,8 @@ pub async fn post_melt_bolt12_quote(
|
||||
pub async fn post_melt_bolt12(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MeltRequest<Uuid>>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<Uuid>>, Response> {
|
||||
Json(payload): Json<MeltRequest<QuoteId>>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
|
||||
@@ -4,6 +4,7 @@ use axum::extract::{Json, Path, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use cdk::error::{ErrorCode, ErrorResponse};
|
||||
use cdk::mint::QuoteId;
|
||||
#[cfg(feature = "auth")]
|
||||
use cdk::nuts::nut21::{Method, ProtectedEndpoint, RoutePath};
|
||||
use cdk::nuts::{
|
||||
@@ -15,7 +16,6 @@ use cdk::nuts::{
|
||||
use cdk::util::unix_time;
|
||||
use paste::paste;
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "auth")]
|
||||
use crate::auth::AuthHeader;
|
||||
@@ -62,11 +62,11 @@ macro_rules! post_cache_wrapper {
|
||||
}
|
||||
|
||||
post_cache_wrapper!(post_swap, SwapRequest, SwapResponse);
|
||||
post_cache_wrapper!(post_mint_bolt11, MintRequest<Uuid>, MintResponse);
|
||||
post_cache_wrapper!(post_mint_bolt11, MintRequest<QuoteId>, MintResponse);
|
||||
post_cache_wrapper!(
|
||||
post_melt_bolt11,
|
||||
MeltRequest<Uuid>,
|
||||
MeltQuoteBolt11Response<Uuid>
|
||||
MeltRequest<QuoteId>,
|
||||
MeltQuoteBolt11Response<QuoteId>
|
||||
);
|
||||
|
||||
#[cfg_attr(feature = "swagger", utoipa::path(
|
||||
@@ -152,7 +152,7 @@ pub(crate) async fn post_mint_bolt11_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MintQuoteBolt11Request>,
|
||||
) -> Result<Json<MintQuoteBolt11Response<Uuid>>, Response> {
|
||||
) -> Result<Json<MintQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
state
|
||||
.mint
|
||||
@@ -191,8 +191,8 @@ pub(crate) async fn post_mint_bolt11_quote(
|
||||
pub(crate) async fn get_check_mint_bolt11_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Path(quote_id): Path<Uuid>,
|
||||
) -> Result<Json<MintQuoteBolt11Response<Uuid>>, Response> {
|
||||
Path(quote_id): Path<QuoteId>,
|
||||
) -> Result<Json<MintQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
@@ -244,7 +244,7 @@ pub(crate) async fn ws_handler(
|
||||
pub(crate) async fn post_mint_bolt11(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MintRequest<Uuid>>,
|
||||
Json(payload): Json<MintRequest<QuoteId>>,
|
||||
) -> Result<Json<MintResponse>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
@@ -286,7 +286,7 @@ pub(crate) async fn post_melt_bolt11_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MeltQuoteBolt11Request>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<Uuid>>, Response> {
|
||||
) -> Result<Json<MeltQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
@@ -327,8 +327,8 @@ pub(crate) async fn post_melt_bolt11_quote(
|
||||
pub(crate) async fn get_check_melt_bolt11_quote(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Path(quote_id): Path<Uuid>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<Uuid>>, Response> {
|
||||
Path(quote_id): Path<QuoteId>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
@@ -370,8 +370,8 @@ pub(crate) async fn get_check_melt_bolt11_quote(
|
||||
pub(crate) async fn post_melt_bolt11(
|
||||
#[cfg(feature = "auth")] auth: AuthHeader,
|
||||
State(state): State<MintState>,
|
||||
Json(payload): Json<MeltRequest<Uuid>>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<Uuid>>, Response> {
|
||||
Json(payload): Json<MeltRequest<QuoteId>>,
|
||||
) -> Result<Json<MeltQuoteBolt11Response<QuoteId>>, Response> {
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
state
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::extract::ws::{Message, WebSocket};
|
||||
use cdk::mint::QuoteId;
|
||||
use cdk::nuts::nut17::NotificationPayload;
|
||||
use cdk::pub_sub::SubId;
|
||||
use cdk::ws::{
|
||||
@@ -9,7 +10,6 @@ use cdk::ws::{
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use tokio::sync::mpsc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::MintState;
|
||||
|
||||
@@ -37,7 +37,7 @@ pub use error::WsError;
|
||||
pub struct WsContext {
|
||||
state: MintState,
|
||||
subscriptions: HashMap<SubId, tokio::task::JoinHandle<()>>,
|
||||
publisher: mpsc::Sender<(SubId, NotificationPayload<Uuid>)>,
|
||||
publisher: mpsc::Sender<(SubId, NotificationPayload<QuoteId>)>,
|
||||
}
|
||||
|
||||
/// Main function for websocket connections
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cashu::quote_id::QuoteId;
|
||||
use cashu::{Amount, MintInfo};
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -64,25 +65,27 @@ pub trait QuotesTransaction<'a> {
|
||||
type Err: Into<Error> + From<Error>;
|
||||
|
||||
/// Get [`MintMintQuote`] and lock it for update in this transaction
|
||||
async fn get_mint_quote(&mut self, quote_id: &Uuid)
|
||||
-> Result<Option<MintMintQuote>, Self::Err>;
|
||||
async fn get_mint_quote(
|
||||
&mut self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Option<MintMintQuote>, Self::Err>;
|
||||
/// Add [`MintMintQuote`]
|
||||
async fn add_mint_quote(&mut self, quote: MintMintQuote) -> Result<(), Self::Err>;
|
||||
/// Increment amount paid [`MintMintQuote`]
|
||||
async fn increment_mint_quote_amount_paid(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
amount_paid: Amount,
|
||||
payment_id: String,
|
||||
) -> Result<Amount, Self::Err>;
|
||||
/// Increment amount paid [`MintMintQuote`]
|
||||
async fn increment_mint_quote_amount_issued(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
amount_issued: Amount,
|
||||
) -> Result<Amount, Self::Err>;
|
||||
/// Remove [`MintMintQuote`]
|
||||
async fn remove_mint_quote(&mut self, quote_id: &Uuid) -> Result<(), Self::Err>;
|
||||
async fn remove_mint_quote(&mut self, quote_id: &QuoteId) -> Result<(), Self::Err>;
|
||||
/// Get [`mint::MeltQuote`] and lock it for update in this transaction
|
||||
async fn get_melt_quote(
|
||||
&mut self,
|
||||
@@ -94,7 +97,7 @@ pub trait QuotesTransaction<'a> {
|
||||
/// Updates the request lookup id for a melt quote
|
||||
async fn update_melt_quote_request_lookup_id(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
new_request_lookup_id: &PaymentIdentifier,
|
||||
) -> Result<(), Self::Err>;
|
||||
|
||||
@@ -103,7 +106,7 @@ pub trait QuotesTransaction<'a> {
|
||||
/// It is expected for this function to fail if the state is already set to the new state
|
||||
async fn update_melt_quote_state(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
new_state: MeltQuoteState,
|
||||
payment_proof: Option<String>,
|
||||
) -> Result<(MeltQuoteState, mint::MeltQuote), Self::Err>;
|
||||
@@ -129,7 +132,7 @@ pub trait QuotesDatabase {
|
||||
type Err: Into<Error> + From<Error>;
|
||||
|
||||
/// Get [`MintMintQuote`]
|
||||
async fn get_mint_quote(&self, quote_id: &Uuid) -> Result<Option<MintMintQuote>, Self::Err>;
|
||||
async fn get_mint_quote(&self, quote_id: &QuoteId) -> Result<Option<MintMintQuote>, Self::Err>;
|
||||
|
||||
/// Get all [`MintMintQuote`]s
|
||||
async fn get_mint_quote_by_request(
|
||||
@@ -144,7 +147,10 @@ pub trait QuotesDatabase {
|
||||
/// Get Mint Quotes
|
||||
async fn get_mint_quotes(&self) -> Result<Vec<MintMintQuote>, Self::Err>;
|
||||
/// Get [`mint::MeltQuote`]
|
||||
async fn get_melt_quote(&self, quote_id: &Uuid) -> Result<Option<mint::MeltQuote>, Self::Err>;
|
||||
async fn get_melt_quote(
|
||||
&self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Option<mint::MeltQuote>, Self::Err>;
|
||||
/// Get all [`mint::MeltQuote`]s
|
||||
async fn get_melt_quotes(&self) -> Result<Vec<mint::MeltQuote>, Self::Err>;
|
||||
}
|
||||
@@ -205,7 +211,7 @@ pub trait SignaturesTransaction<'a> {
|
||||
&mut self,
|
||||
blinded_messages: &[PublicKey],
|
||||
blind_signatures: &[BlindSignature],
|
||||
quote_id: Option<Uuid>,
|
||||
quote_id: Option<QuoteId>,
|
||||
) -> Result<(), Self::Err>;
|
||||
|
||||
/// Get [`BlindSignature`]s
|
||||
@@ -234,7 +240,7 @@ pub trait SignaturesDatabase {
|
||||
/// Get [`BlindSignature`]s for quote
|
||||
async fn get_blind_signatures_for_quote(
|
||||
&self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Vec<BlindSignature>, Self::Err>;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,13 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
#[cfg(feature = "auth")]
|
||||
NUT22(#[from] crate::nuts::nut22::Error),
|
||||
/// NUT04 Error
|
||||
#[error(transparent)]
|
||||
NUT04(#[from] crate::nuts::nut04::Error),
|
||||
/// Quote ID Error
|
||||
#[error(transparent)]
|
||||
#[cfg(feature = "mint")]
|
||||
QuoteId(#[from] crate::quote_id::QuoteIdError),
|
||||
/// Serde Error
|
||||
#[error(transparent)]
|
||||
Serde(#[from] serde_json::Error),
|
||||
|
||||
@@ -363,6 +363,10 @@ pub enum Error {
|
||||
/// NUT23 Error
|
||||
#[error(transparent)]
|
||||
NUT23(#[from] crate::nuts::nut23::Error),
|
||||
/// Quote ID Error
|
||||
#[error(transparent)]
|
||||
#[cfg(feature = "mint")]
|
||||
QuoteId(#[from] crate::quote_id::QuoteIdError),
|
||||
/// From slice error
|
||||
#[error(transparent)]
|
||||
TryFromSliceError(#[from] TryFromSliceError),
|
||||
|
||||
@@ -29,5 +29,7 @@ pub use bitcoin;
|
||||
pub use cashu::amount::{self, Amount};
|
||||
pub use cashu::lightning_invoice::{self, Bolt11Invoice};
|
||||
pub use cashu::nuts::{self, *};
|
||||
#[cfg(feature = "mint")]
|
||||
pub use cashu::quote_id::{self, *};
|
||||
pub use cashu::{dhke, ensure_cdk, mint_url, secret, util, SECP256K1};
|
||||
pub use error::Error;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Mint types
|
||||
|
||||
use bitcoin::bip32::DerivationPath;
|
||||
use cashu::quote_id::QuoteId;
|
||||
use cashu::util::unix_time;
|
||||
use cashu::{
|
||||
Bolt11Invoice, MeltOptions, MeltQuoteBolt11Response, MintQuoteBolt11Response,
|
||||
@@ -19,7 +20,7 @@ use crate::{Amount, CurrencyUnit, Id, KeySetInfo, PublicKey};
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MintQuote {
|
||||
/// Quote id
|
||||
pub id: Uuid,
|
||||
pub id: QuoteId,
|
||||
/// Amount of quote
|
||||
pub amount: Option<Amount>,
|
||||
/// Unit of quote
|
||||
@@ -56,7 +57,7 @@ impl MintQuote {
|
||||
/// Create new [`MintQuote`]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
id: Option<Uuid>,
|
||||
id: Option<QuoteId>,
|
||||
request: String,
|
||||
unit: CurrencyUnit,
|
||||
amount: Option<Amount>,
|
||||
@@ -70,7 +71,7 @@ impl MintQuote {
|
||||
payments: Vec<IncomingPayment>,
|
||||
issuance: Vec<Issuance>,
|
||||
) -> Self {
|
||||
let id = id.unwrap_or(Uuid::new_v4());
|
||||
let id = id.unwrap_or_else(QuoteId::new_uuid);
|
||||
|
||||
Self {
|
||||
id,
|
||||
@@ -230,7 +231,7 @@ impl Issuance {
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MeltQuote {
|
||||
/// Quote id
|
||||
pub id: Uuid,
|
||||
pub id: QuoteId,
|
||||
/// Quote unit
|
||||
pub unit: CurrencyUnit,
|
||||
/// Quote amount
|
||||
@@ -277,7 +278,7 @@ impl MeltQuote {
|
||||
let id = Uuid::new_v4();
|
||||
|
||||
Self {
|
||||
id,
|
||||
id: QuoteId::UUID(id),
|
||||
amount,
|
||||
unit,
|
||||
request,
|
||||
@@ -336,10 +337,10 @@ impl From<MintKeySetInfo> for KeySetInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MintQuote> for MintQuoteBolt11Response<Uuid> {
|
||||
fn from(mint_quote: crate::mint::MintQuote) -> MintQuoteBolt11Response<Uuid> {
|
||||
impl From<MintQuote> for MintQuoteBolt11Response<QuoteId> {
|
||||
fn from(mint_quote: crate::mint::MintQuote) -> MintQuoteBolt11Response<QuoteId> {
|
||||
MintQuoteBolt11Response {
|
||||
quote: mint_quote.id,
|
||||
quote: mint_quote.id.clone(),
|
||||
state: mint_quote.state(),
|
||||
request: mint_quote.request,
|
||||
expiry: Some(mint_quote.expiry),
|
||||
@@ -352,18 +353,18 @@ impl From<MintQuote> for MintQuoteBolt11Response<Uuid> {
|
||||
|
||||
impl From<MintQuote> for MintQuoteBolt11Response<String> {
|
||||
fn from(quote: MintQuote) -> Self {
|
||||
let quote: MintQuoteBolt11Response<Uuid> = quote.into();
|
||||
let quote: MintQuoteBolt11Response<QuoteId> = quote.into();
|
||||
|
||||
quote.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::mint::MintQuote> for MintQuoteBolt12Response<Uuid> {
|
||||
impl TryFrom<crate::mint::MintQuote> for MintQuoteBolt12Response<QuoteId> {
|
||||
type Error = crate::Error;
|
||||
|
||||
fn try_from(mint_quote: crate::mint::MintQuote) -> Result<Self, Self::Error> {
|
||||
Ok(MintQuoteBolt12Response {
|
||||
quote: mint_quote.id,
|
||||
quote: mint_quote.id.clone(),
|
||||
request: mint_quote.request,
|
||||
expiry: Some(mint_quote.expiry),
|
||||
amount_paid: mint_quote.amount_paid,
|
||||
@@ -379,16 +380,16 @@ impl TryFrom<MintQuote> for MintQuoteBolt12Response<String> {
|
||||
type Error = crate::Error;
|
||||
|
||||
fn try_from(quote: MintQuote) -> Result<Self, Self::Error> {
|
||||
let quote: MintQuoteBolt12Response<Uuid> = quote.try_into()?;
|
||||
let quote: MintQuoteBolt12Response<QuoteId> = quote.try_into()?;
|
||||
|
||||
Ok(quote.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&MeltQuote> for MeltQuoteBolt11Response<Uuid> {
|
||||
fn from(melt_quote: &MeltQuote) -> MeltQuoteBolt11Response<Uuid> {
|
||||
impl From<&MeltQuote> for MeltQuoteBolt11Response<QuoteId> {
|
||||
fn from(melt_quote: &MeltQuote) -> MeltQuoteBolt11Response<QuoteId> {
|
||||
MeltQuoteBolt11Response {
|
||||
quote: melt_quote.id,
|
||||
quote: melt_quote.id.clone(),
|
||||
payment_preimage: None,
|
||||
change: None,
|
||||
state: melt_quote.state,
|
||||
@@ -402,11 +403,11 @@ impl From<&MeltQuote> for MeltQuoteBolt11Response<Uuid> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MeltQuote> for MeltQuoteBolt11Response<Uuid> {
|
||||
fn from(melt_quote: MeltQuote) -> MeltQuoteBolt11Response<Uuid> {
|
||||
impl From<MeltQuote> for MeltQuoteBolt11Response<QuoteId> {
|
||||
fn from(melt_quote: MeltQuote) -> MeltQuoteBolt11Response<QuoteId> {
|
||||
let paid = melt_quote.state == MeltQuoteState::Paid;
|
||||
MeltQuoteBolt11Response {
|
||||
quote: melt_quote.id,
|
||||
quote: melt_quote.id.clone(),
|
||||
amount: melt_quote.amount,
|
||||
fee_reserve: melt_quote.fee_reserve,
|
||||
paid: Some(paid),
|
||||
|
||||
@@ -6,11 +6,11 @@ use cashu::nut17::{self};
|
||||
#[cfg(feature = "mint")]
|
||||
use cashu::nut17::{Error, Kind, Notification};
|
||||
#[cfg(feature = "mint")]
|
||||
use cashu::quote_id::QuoteId;
|
||||
#[cfg(feature = "mint")]
|
||||
use cashu::{NotificationPayload, PublicKey};
|
||||
#[cfg(feature = "mint")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
use crate::pub_sub::index::{Index, Indexable, SubscriptionGlobalId};
|
||||
@@ -45,14 +45,14 @@ impl TryFrom<IndexableParams> for Vec<Index<Notification>> {
|
||||
.map(|filter| {
|
||||
let idx = match params.kind {
|
||||
Kind::Bolt11MeltQuote => {
|
||||
Notification::MeltQuoteBolt11(Uuid::from_str(&filter)?)
|
||||
Notification::MeltQuoteBolt11(QuoteId::from_str(&filter)?)
|
||||
}
|
||||
Kind::Bolt11MintQuote => {
|
||||
Notification::MintQuoteBolt11(Uuid::from_str(&filter)?)
|
||||
Notification::MintQuoteBolt11(QuoteId::from_str(&filter)?)
|
||||
}
|
||||
Kind::ProofState => Notification::ProofState(PublicKey::from_str(&filter)?),
|
||||
Kind::Bolt12MintQuote => {
|
||||
Notification::MintQuoteBolt12(Uuid::from_str(&filter)?)
|
||||
Notification::MintQuoteBolt12(QuoteId::from_str(&filter)?)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ impl AsRef<SubId> for IndexableParams {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
impl Indexable for NotificationPayload<Uuid> {
|
||||
impl Indexable for NotificationPayload<QuoteId> {
|
||||
type Type = Notification;
|
||||
|
||||
fn to_indexes(&self) -> Vec<Index<Self::Type>> {
|
||||
@@ -79,13 +79,19 @@ impl Indexable for NotificationPayload<Uuid> {
|
||||
vec![Index::from(Notification::ProofState(proof_state.y))]
|
||||
}
|
||||
NotificationPayload::MeltQuoteBolt11Response(melt_quote) => {
|
||||
vec![Index::from(Notification::MeltQuoteBolt11(melt_quote.quote))]
|
||||
vec![Index::from(Notification::MeltQuoteBolt11(
|
||||
melt_quote.quote.clone(),
|
||||
))]
|
||||
}
|
||||
NotificationPayload::MintQuoteBolt11Response(mint_quote) => {
|
||||
vec![Index::from(Notification::MintQuoteBolt11(mint_quote.quote))]
|
||||
vec![Index::from(Notification::MintQuoteBolt11(
|
||||
mint_quote.quote.clone(),
|
||||
))]
|
||||
}
|
||||
NotificationPayload::MintQuoteBolt12Response(mint_quote) => {
|
||||
vec![Index::from(Notification::MintQuoteBolt12(mint_quote.quote))]
|
||||
vec![Index::from(Notification::MintQuoteBolt12(
|
||||
mint_quote.quote.clone(),
|
||||
))]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
use cashu::nut17::ws::JSON_RPC_VERSION;
|
||||
use cashu::nut17::{self};
|
||||
#[cfg(feature = "mint")]
|
||||
use cashu::NotificationPayload;
|
||||
use cashu::quote_id::QuoteId;
|
||||
#[cfg(feature = "mint")]
|
||||
use uuid::Uuid;
|
||||
use cashu::NotificationPayload;
|
||||
|
||||
use crate::pub_sub::SubId;
|
||||
|
||||
@@ -48,7 +48,7 @@ pub type NotificationInner<T> = nut17::ws::NotificationInner<T, SubId>;
|
||||
#[cfg(feature = "mint")]
|
||||
/// Converts a notification with UUID identifiers to a notification with string identifiers
|
||||
pub fn notification_uuid_to_notification_string(
|
||||
notification: NotificationInner<Uuid>,
|
||||
notification: NotificationInner<QuoteId>,
|
||||
) -> NotificationInner<String> {
|
||||
nut17::ws::NotificationInner {
|
||||
sub_id: notification.sub_id,
|
||||
@@ -69,7 +69,7 @@ pub fn notification_uuid_to_notification_string(
|
||||
|
||||
#[cfg(feature = "mint")]
|
||||
/// Converts a notification to a websocket message that can be sent to clients
|
||||
pub fn notification_to_ws_message(notification: NotificationInner<Uuid>) -> WsMessageOrResponse {
|
||||
pub fn notification_to_ws_message(notification: NotificationInner<QuoteId>) -> WsMessageOrResponse {
|
||||
nut17::ws::WsMessageOrResponse::Notification(nut17::ws::WsNotification {
|
||||
jsonrpc: JSON_RPC_VERSION.to_owned(),
|
||||
method: "subscribe".to_string(),
|
||||
|
||||
@@ -260,6 +260,7 @@ fn create_ldk_settings(
|
||||
url: format!("http://127.0.0.1:{port}"),
|
||||
listen_host: "127.0.0.1".to_string(),
|
||||
listen_port: port,
|
||||
seed: None,
|
||||
mnemonic: Some(mnemonic),
|
||||
signatory_url: None,
|
||||
signatory_certs: None,
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::{env, fs};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use bip39::Mnemonic;
|
||||
use cashu::quote_id::QuoteId;
|
||||
use cashu::{MeltQuoteBolt12Request, MintQuoteBolt12Request, MintQuoteBolt12Response};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::{self, MintDatabase, WalletDatabase};
|
||||
@@ -80,16 +81,15 @@ impl MintConnector for DirectMintConnection {
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MintQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_mint_quote("e_id_uuid)
|
||||
.check_mint_quote(&QuoteId::from_str(quote_id)?)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_mint(&self, request: MintRequest<String>) -> Result<MintResponse, Error> {
|
||||
let request_uuid = request.try_into().unwrap();
|
||||
self.mint.process_mint_request(request_uuid).await
|
||||
let request_id: MintRequest<QuoteId> = request.try_into().unwrap();
|
||||
self.mint.process_mint_request(request_id).await
|
||||
}
|
||||
|
||||
async fn post_melt_quote(
|
||||
@@ -106,9 +106,8 @@ impl MintConnector for DirectMintConnection {
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_melt_quote("e_id_uuid)
|
||||
.check_melt_quote(&QuoteId::from_str(quote_id)?)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
@@ -156,7 +155,7 @@ impl MintConnector for DirectMintConnection {
|
||||
&self,
|
||||
request: MintQuoteBolt12Request,
|
||||
) -> Result<MintQuoteBolt12Response<String>, Error> {
|
||||
let res: MintQuoteBolt12Response<Uuid> =
|
||||
let res: MintQuoteBolt12Response<QuoteId> =
|
||||
self.mint.get_mint_quote(request.into()).await?.try_into()?;
|
||||
Ok(res.into())
|
||||
}
|
||||
@@ -165,10 +164,9 @@ impl MintConnector for DirectMintConnection {
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MintQuoteBolt12Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
let quote: MintQuoteBolt12Response<Uuid> = self
|
||||
let quote: MintQuoteBolt12Response<QuoteId> = self
|
||||
.mint
|
||||
.check_mint_quote("e_id_uuid)
|
||||
.check_mint_quote(&QuoteId::from_str(quote_id)?)
|
||||
.await?
|
||||
.try_into()?;
|
||||
|
||||
@@ -190,9 +188,8 @@ impl MintConnector for DirectMintConnection {
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_melt_quote("e_id_uuid)
|
||||
.check_melt_quote(&QuoteId::from_str(quote_id)?)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ pub fn create_fake_wallet_settings(
|
||||
url: format!("http://127.0.0.1:{port}"),
|
||||
listen_host: "127.0.0.1".to_string(),
|
||||
listen_port: port,
|
||||
seed: None,
|
||||
mnemonic,
|
||||
signatory_url: signatory_config.as_ref().map(|(url, _)| url.clone()),
|
||||
signatory_certs: signatory_config
|
||||
@@ -233,6 +234,7 @@ pub fn create_cln_settings(
|
||||
url: format!("http://127.0.0.1:{port}"),
|
||||
listen_host: "127.0.0.1".to_string(),
|
||||
listen_port: port,
|
||||
seed: None,
|
||||
mnemonic: Some(mnemonic),
|
||||
signatory_url: None,
|
||||
signatory_certs: None,
|
||||
@@ -277,6 +279,7 @@ pub fn create_lnd_settings(
|
||||
url: format!("http://127.0.0.1:{port}"),
|
||||
listen_host: "127.0.0.1".to_string(),
|
||||
listen_port: port,
|
||||
seed: None,
|
||||
mnemonic: Some(mnemonic),
|
||||
signatory_url: None,
|
||||
signatory_certs: None,
|
||||
|
||||
@@ -677,7 +677,7 @@ impl CdkMint for MintRPCServer {
|
||||
_ => {
|
||||
// Create a new quote with the same values
|
||||
let quote = MintQuote::new(
|
||||
Some(mint_quote.id), // id
|
||||
Some(mint_quote.id.clone()), // id
|
||||
mint_quote.request.clone(), // request
|
||||
mint_quote.unit.clone(), // unit
|
||||
mint_quote.amount, // amount
|
||||
|
||||
@@ -50,6 +50,8 @@ pub struct Info {
|
||||
pub url: String,
|
||||
pub listen_host: String,
|
||||
pub listen_port: u16,
|
||||
/// Overrides mnemonic
|
||||
pub seed: Option<String>,
|
||||
pub mnemonic: Option<String>,
|
||||
pub signatory_url: Option<String>,
|
||||
pub signatory_certs: Option<String>,
|
||||
@@ -74,6 +76,7 @@ impl Default for Info {
|
||||
url: String::new(),
|
||||
listen_host: "127.0.0.1".to_string(),
|
||||
listen_port: 8091, // Default to port 8091 instead of 0
|
||||
seed: None,
|
||||
mnemonic: None,
|
||||
signatory_url: None,
|
||||
signatory_certs: None,
|
||||
@@ -88,7 +91,7 @@ impl Default for Info {
|
||||
impl std::fmt::Debug for Info {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Use a fallback approach that won't panic
|
||||
let mnemonic_display = {
|
||||
let mnemonic_display: String = {
|
||||
if let Some(mnemonic) = self.mnemonic.as_ref() {
|
||||
let hash = sha256::Hash::hash(mnemonic.as_bytes());
|
||||
format!("<hashed: {hash}>")
|
||||
|
||||
@@ -6,6 +6,7 @@ pub const DATABASE_URL_ENV_VAR: &str = "CDK_MINTD_DATABASE_URL"; // Legacy, main
|
||||
pub const ENV_URL: &str = "CDK_MINTD_URL";
|
||||
pub const ENV_LISTEN_HOST: &str = "CDK_MINTD_LISTEN_HOST";
|
||||
pub const ENV_LISTEN_PORT: &str = "CDK_MINTD_LISTEN_PORT";
|
||||
pub const ENV_SEED: &str = "CDK_MINTD_SEED";
|
||||
pub const ENV_MNEMONIC: &str = "CDK_MINTD_MNEMONIC";
|
||||
pub const ENV_SIGNATORY_URL: &str = "CDK_MINTD_SIGNATORY_URL";
|
||||
pub const ENV_SIGNATORY_CERTS: &str = "CDK_MINTD_SIGNATORY_CERTS";
|
||||
|
||||
@@ -31,6 +31,10 @@ impl Info {
|
||||
self.signatory_certs = Some(signatory_certs);
|
||||
}
|
||||
|
||||
if let Ok(seed) = env::var(ENV_SEED) {
|
||||
self.seed = Some(seed);
|
||||
}
|
||||
|
||||
if let Ok(mnemonic) = env::var(ENV_MNEMONIC) {
|
||||
self.mnemonic = Some(mnemonic);
|
||||
}
|
||||
|
||||
@@ -805,6 +805,9 @@ async fn build_mint(
|
||||
.await?,
|
||||
))
|
||||
.await?)
|
||||
} else if let Some(seed) = settings.info.seed.clone() {
|
||||
let seed_bytes: Vec<u8> = seed.into();
|
||||
Ok(mint_builder.build_with_seed(keystore, &seed_bytes).await?)
|
||||
} else if let Some(mnemonic) = settings
|
||||
.info
|
||||
.mnemonic
|
||||
|
||||
@@ -26,6 +26,7 @@ use cdk_common::mint::{
|
||||
};
|
||||
use cdk_common::nut00::ProofsMethods;
|
||||
use cdk_common::payment::PaymentIdentifier;
|
||||
use cdk_common::quote_id::QuoteId;
|
||||
use cdk_common::secret::Secret;
|
||||
use cdk_common::state::check_state_transition;
|
||||
use cdk_common::util::unix_time;
|
||||
@@ -309,7 +310,7 @@ where
|
||||
#[inline(always)]
|
||||
async fn get_mint_quote_payments<C>(
|
||||
conn: &C,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Vec<IncomingPayment>, Error>
|
||||
where
|
||||
C: DatabaseExecutor + Send + Sync,
|
||||
@@ -327,7 +328,13 @@ where
|
||||
quote_id=:quote_id
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_all(conn)
|
||||
.await?
|
||||
.into_iter()
|
||||
@@ -344,7 +351,7 @@ where
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
async fn get_mint_quote_issuance<C>(conn: &C, quote_id: &Uuid) -> Result<Vec<Issuance>, Error>
|
||||
async fn get_mint_quote_issuance<C>(conn: &C, quote_id: &QuoteId) -> Result<Vec<Issuance>, Error>
|
||||
where
|
||||
C: DatabaseExecutor + Send + Sync,
|
||||
{
|
||||
@@ -356,7 +363,13 @@ FROM mint_quote_issued
|
||||
WHERE quote_id=:quote_id
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_all(conn)
|
||||
.await?
|
||||
.into_iter()
|
||||
@@ -542,7 +555,7 @@ where
|
||||
#[instrument(skip(self))]
|
||||
async fn increment_mint_quote_amount_paid(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
amount_paid: Amount,
|
||||
payment_id: String,
|
||||
) -> Result<Amount, Self::Err> {
|
||||
@@ -578,7 +591,13 @@ where
|
||||
FOR UPDATE
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_one(&self.inner)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
@@ -613,7 +632,13 @@ where
|
||||
"#,
|
||||
)?
|
||||
.bind("amount_paid", new_amount_paid.to_i64())
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.execute(&self.inner)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
@@ -628,7 +653,13 @@ where
|
||||
VALUES (:quote_id, :payment_id, :amount, :timestamp)
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.bind("payment_id", payment_id)
|
||||
.bind("amount", amount_paid.to_i64())
|
||||
.bind("timestamp", unix_time() as i64)
|
||||
@@ -645,7 +676,7 @@ where
|
||||
#[instrument(skip_all)]
|
||||
async fn increment_mint_quote_amount_issued(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
amount_issued: Amount,
|
||||
) -> Result<Amount, Self::Err> {
|
||||
// Get current amount_issued from quote
|
||||
@@ -657,7 +688,13 @@ where
|
||||
FOR UPDATE
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_one(&self.inner)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
@@ -685,7 +722,13 @@ where
|
||||
"#,
|
||||
)?
|
||||
.bind("amount_issued", new_amount_issued.to_i64())
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.execute(&self.inner)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
@@ -701,7 +744,13 @@ INSERT INTO mint_quote_issued
|
||||
VALUES (:quote_id, :amount, :timestamp);
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.bind("amount", amount_issued.to_i64())
|
||||
.bind("timestamp", current_time as i64)
|
||||
.execute(&self.inner)
|
||||
@@ -741,9 +790,15 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_mint_quote(&mut self, quote_id: &Uuid) -> Result<(), Self::Err> {
|
||||
async fn remove_mint_quote(&mut self, quote_id: &QuoteId) -> Result<(), Self::Err> {
|
||||
query(r#"DELETE FROM mint_quote WHERE id=:id"#)?
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.execute(&self.inner)
|
||||
.await?;
|
||||
Ok(())
|
||||
@@ -800,13 +855,16 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
|
||||
async fn update_melt_quote_request_lookup_id(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
new_request_lookup_id: &PaymentIdentifier,
|
||||
) -> Result<(), Self::Err> {
|
||||
query(r#"UPDATE melt_quote SET request_lookup_id = :new_req_id, request_lookup_id_kind = :new_kind WHERE id = :id"#)?
|
||||
.bind("new_req_id", new_request_lookup_id.to_string())
|
||||
.bind("new_kind",new_request_lookup_id.kind() )
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind("id", match quote_id {
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
})
|
||||
.execute(&self.inner)
|
||||
.await?;
|
||||
Ok(())
|
||||
@@ -814,7 +872,7 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
|
||||
async fn update_melt_quote_state(
|
||||
&mut self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
state: MeltQuoteState,
|
||||
payment_proof: Option<String>,
|
||||
) -> Result<(MeltQuoteState, mint::MeltQuote), Self::Err> {
|
||||
@@ -842,7 +900,13 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
AND state != :state
|
||||
"#,
|
||||
)?
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.bind("state", state.to_string())
|
||||
.fetch_one(&self.inner)
|
||||
.await?
|
||||
@@ -856,13 +920,22 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
.bind("state", state.to_string())
|
||||
.bind("paid_time", current_time as i64)
|
||||
.bind("payment_preimage", payment_proof)
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind("id", match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
})
|
||||
.execute(&self.inner)
|
||||
.await
|
||||
} else {
|
||||
query(r#"UPDATE melt_quote SET state = :state WHERE id = :id"#)?
|
||||
.bind("state", state.to_string())
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.execute(&self.inner)
|
||||
.await
|
||||
};
|
||||
@@ -895,7 +968,7 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_mint_quote(&mut self, quote_id: &Uuid) -> Result<Option<MintQuote>, Self::Err> {
|
||||
async fn get_mint_quote(&mut self, quote_id: &QuoteId) -> Result<Option<MintQuote>, Self::Err> {
|
||||
let payments = get_mint_quote_payments(&self.inner, quote_id).await?;
|
||||
let issuance = get_mint_quote_issuance(&self.inner, quote_id).await?;
|
||||
|
||||
@@ -920,7 +993,13 @@ VALUES (:quote_id, :amount, :timestamp);
|
||||
FOR UPDATE
|
||||
"#,
|
||||
)?
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_one(&self.inner)
|
||||
.await?
|
||||
.map(|row| sql_row_to_mint_quote(row, payments, issuance))
|
||||
@@ -1053,7 +1132,7 @@ where
|
||||
{
|
||||
type Err = Error;
|
||||
|
||||
async fn get_mint_quote(&self, quote_id: &Uuid) -> Result<Option<MintQuote>, Self::Err> {
|
||||
async fn get_mint_quote(&self, quote_id: &QuoteId) -> Result<Option<MintQuote>, Self::Err> {
|
||||
let conn = self.pool.get().map_err(|e| Error::Database(Box::new(e)))?;
|
||||
|
||||
let payments = get_mint_quote_payments(&*conn, quote_id).await?;
|
||||
@@ -1078,7 +1157,13 @@ where
|
||||
mint_quote
|
||||
WHERE id = :id"#,
|
||||
)?
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"id",
|
||||
match quote_id {
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_one(&*conn)
|
||||
.await?
|
||||
.map(|row| sql_row_to_mint_quote(row, payments, issuance))
|
||||
@@ -1206,7 +1291,10 @@ where
|
||||
Ok(mint_quotes)
|
||||
}
|
||||
|
||||
async fn get_melt_quote(&self, quote_id: &Uuid) -> Result<Option<mint::MeltQuote>, Self::Err> {
|
||||
async fn get_melt_quote(
|
||||
&self,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Option<mint::MeltQuote>, Self::Err> {
|
||||
let conn = self.pool.get().map_err(|e| Error::Database(Box::new(e)))?;
|
||||
Ok(query(
|
||||
r#"
|
||||
@@ -1231,7 +1319,13 @@ where
|
||||
id=:id
|
||||
"#,
|
||||
)?
|
||||
.bind("id", quote_id.as_hyphenated().to_string())
|
||||
.bind(
|
||||
"id",
|
||||
match quote_id {
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_one(&*conn)
|
||||
.await?
|
||||
.map(sql_row_to_melt_quote)
|
||||
@@ -1386,7 +1480,7 @@ where
|
||||
&mut self,
|
||||
blinded_messages: &[PublicKey],
|
||||
blind_signatures: &[BlindSignature],
|
||||
quote_id: Option<Uuid>,
|
||||
quote_id: Option<QuoteId>,
|
||||
) -> Result<(), Self::Err> {
|
||||
let current_time = unix_time();
|
||||
|
||||
@@ -1403,7 +1497,10 @@ where
|
||||
.bind("amount", u64::from(signature.amount) as i64)
|
||||
.bind("keyset_id", signature.keyset_id.to_string())
|
||||
.bind("c", signature.c.to_bytes().to_vec())
|
||||
.bind("quote_id", quote_id.map(|q| q.hyphenated().to_string()))
|
||||
.bind("quote_id", quote_id.as_ref().map(|q| match q {
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
QuoteId::UUID(u) => u.hyphenated().to_string(),
|
||||
}))
|
||||
.bind(
|
||||
"dleq_e",
|
||||
signature.dleq.as_ref().map(|dleq| dleq.e.to_secret_hex()),
|
||||
@@ -1547,7 +1644,7 @@ where
|
||||
/// Get [`BlindSignature`]s for quote
|
||||
async fn get_blind_signatures_for_quote(
|
||||
&self,
|
||||
quote_id: &Uuid,
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<Vec<BlindSignature>, Self::Err> {
|
||||
let conn = self.pool.get().map_err(|e| Error::Database(Box::new(e)))?;
|
||||
Ok(query(
|
||||
@@ -1564,7 +1661,13 @@ where
|
||||
quote_id=:quote_id
|
||||
"#,
|
||||
)?
|
||||
.bind("quote_id", quote_id.to_string())
|
||||
.bind(
|
||||
"quote_id",
|
||||
match quote_id {
|
||||
QuoteId::BASE64(s) => s.to_string(),
|
||||
QuoteId::UUID(u) => u.as_hyphenated().to_string(),
|
||||
},
|
||||
)
|
||||
.fetch_all(&*conn)
|
||||
.await?
|
||||
.into_iter()
|
||||
@@ -1658,7 +1761,7 @@ fn sql_row_to_mint_quote(
|
||||
let payment_method = column_as_string!(payment_method, PaymentMethod::from_str);
|
||||
|
||||
Ok(MintQuote::new(
|
||||
Some(Uuid::parse_str(&id).map_err(|_| Error::InvalidUuid(id))?),
|
||||
Some(QuoteId::from_str(&id)?),
|
||||
request_str,
|
||||
column_as_string!(unit, CurrencyUnit::from_str),
|
||||
amount.map(Amount::from),
|
||||
@@ -1745,7 +1848,7 @@ fn sql_row_to_melt_quote(row: Vec<Column>) -> Result<mint::MeltQuote, Error> {
|
||||
};
|
||||
|
||||
Ok(MeltQuote {
|
||||
id: Uuid::parse_str(&id).map_err(|_| Error::InvalidUuid(id))?,
|
||||
id: QuoteId::from_str(&id)?,
|
||||
unit: CurrencyUnit::from_str(&unit)?,
|
||||
amount: Amount::from(amount),
|
||||
request,
|
||||
|
||||
@@ -3,6 +3,7 @@ use cdk_common::payment::{
|
||||
Bolt11IncomingPaymentOptions, Bolt11Settings, Bolt12IncomingPaymentOptions,
|
||||
IncomingPaymentOptions, WaitPaymentResponse,
|
||||
};
|
||||
use cdk_common::quote_id::QuoteId;
|
||||
use cdk_common::util::unix_time;
|
||||
use cdk_common::{
|
||||
database, ensure_cdk, Amount, CurrencyUnit, Error, MintQuoteBolt11Request,
|
||||
@@ -10,7 +11,6 @@ use cdk_common::{
|
||||
MintRequest, MintResponse, NotificationPayload, PaymentMethod, PublicKey,
|
||||
};
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::mint::Verification;
|
||||
use crate::Mint;
|
||||
@@ -49,12 +49,12 @@ impl From<MintQuoteBolt12Request> for MintQuoteRequest {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum MintQuoteResponse {
|
||||
/// Lightning Network BOLT11 invoice response
|
||||
Bolt11(MintQuoteBolt11Response<Uuid>),
|
||||
Bolt11(MintQuoteBolt11Response<QuoteId>),
|
||||
/// Lightning Network BOLT12 offer response
|
||||
Bolt12(MintQuoteBolt12Response<Uuid>),
|
||||
Bolt12(MintQuoteBolt12Response<QuoteId>),
|
||||
}
|
||||
|
||||
impl TryFrom<MintQuoteResponse> for MintQuoteBolt11Response<Uuid> {
|
||||
impl TryFrom<MintQuoteResponse> for MintQuoteBolt11Response<QuoteId> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(response: MintQuoteResponse) -> Result<Self, Self::Error> {
|
||||
@@ -65,7 +65,7 @@ impl TryFrom<MintQuoteResponse> for MintQuoteBolt11Response<Uuid> {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<MintQuoteResponse> for MintQuoteBolt12Response<Uuid> {
|
||||
impl TryFrom<MintQuoteResponse> for MintQuoteBolt12Response<QuoteId> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(response: MintQuoteResponse) -> Result<Self, Self::Error> {
|
||||
@@ -82,7 +82,7 @@ impl TryFrom<MintQuote> for MintQuoteResponse {
|
||||
fn try_from(quote: MintQuote) -> Result<Self, Self::Error> {
|
||||
match quote.payment_method {
|
||||
PaymentMethod::Bolt11 => {
|
||||
let bolt11_response: MintQuoteBolt11Response<Uuid> = quote.into();
|
||||
let bolt11_response: MintQuoteBolt11Response<QuoteId> = quote.into();
|
||||
Ok(MintQuoteResponse::Bolt11(bolt11_response))
|
||||
}
|
||||
PaymentMethod::Bolt12 => {
|
||||
@@ -298,12 +298,12 @@ impl Mint {
|
||||
|
||||
match payment_method {
|
||||
PaymentMethod::Bolt11 => {
|
||||
let res: MintQuoteBolt11Response<Uuid> = quote.clone().into();
|
||||
let res: MintQuoteBolt11Response<QuoteId> = quote.clone().into();
|
||||
self.pubsub_manager
|
||||
.broadcast(NotificationPayload::MintQuoteBolt11Response(res));
|
||||
}
|
||||
PaymentMethod::Bolt12 => {
|
||||
let res: MintQuoteBolt12Response<Uuid> = quote.clone().try_into()?;
|
||||
let res: MintQuoteBolt12Response<QuoteId> = quote.clone().try_into()?;
|
||||
self.pubsub_manager
|
||||
.broadcast(NotificationPayload::MintQuoteBolt12Response(res));
|
||||
}
|
||||
@@ -333,7 +333,7 @@ impl Mint {
|
||||
/// * `Ok(())` if removal was successful
|
||||
/// * `Error` if the quote doesn't exist or removal fails
|
||||
#[instrument(skip_all)]
|
||||
pub async fn remove_mint_quote(&self, quote_id: &Uuid) -> Result<(), Error> {
|
||||
pub async fn remove_mint_quote(&self, quote_id: &QuoteId) -> Result<(), Error> {
|
||||
let mut tx = self.localstore.begin_transaction().await?;
|
||||
tx.remove_mint_quote(quote_id).await?;
|
||||
tx.commit().await?;
|
||||
@@ -421,7 +421,7 @@ impl Mint {
|
||||
/// * `MintQuoteResponse` - The current state of the quote
|
||||
/// * `Error` if the quote doesn't exist or checking fails
|
||||
#[instrument(skip(self))]
|
||||
pub async fn check_mint_quote(&self, quote_id: &Uuid) -> Result<MintQuoteResponse, Error> {
|
||||
pub async fn check_mint_quote(&self, quote_id: &QuoteId) -> Result<MintQuoteResponse, Error> {
|
||||
let mut quote = self
|
||||
.localstore
|
||||
.get_mint_quote(quote_id)
|
||||
@@ -454,7 +454,7 @@ impl Mint {
|
||||
#[instrument(skip_all)]
|
||||
pub async fn process_mint_request(
|
||||
&self,
|
||||
mint_request: MintRequest<Uuid>,
|
||||
mint_request: MintRequest<QuoteId>,
|
||||
) -> Result<MintResponse, Error> {
|
||||
let mut mint_quote = self
|
||||
.localstore
|
||||
@@ -563,7 +563,7 @@ impl Mint {
|
||||
.map(|p| p.blinded_secret)
|
||||
.collect::<Vec<PublicKey>>(),
|
||||
&blind_signatures,
|
||||
Some(mint_request.quote),
|
||||
Some(mint_request.quote.clone()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ use cdk_common::payment::{
|
||||
Bolt11OutgoingPaymentOptions, Bolt12OutgoingPaymentOptions, OutgoingPaymentOptions,
|
||||
PaymentIdentifier,
|
||||
};
|
||||
use cdk_common::quote_id::QuoteId;
|
||||
use cdk_common::{MeltOptions, MeltQuoteBolt12Request};
|
||||
use lightning::offers::offer::Offer;
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{
|
||||
CurrencyUnit, MeltQuote, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MeltRequest, Mint,
|
||||
@@ -114,7 +114,7 @@ impl Mint {
|
||||
pub async fn get_melt_quote(
|
||||
&self,
|
||||
melt_quote_request: MeltQuoteRequest,
|
||||
) -> Result<MeltQuoteBolt11Response<Uuid>, Error> {
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
match melt_quote_request {
|
||||
MeltQuoteRequest::Bolt11(bolt11_request) => {
|
||||
self.get_melt_bolt11_quote_impl(&bolt11_request).await
|
||||
@@ -130,7 +130,7 @@ impl Mint {
|
||||
async fn get_melt_bolt11_quote_impl(
|
||||
&self,
|
||||
melt_request: &MeltQuoteBolt11Request,
|
||||
) -> Result<MeltQuoteBolt11Response<Uuid>, Error> {
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
let MeltQuoteBolt11Request {
|
||||
request,
|
||||
unit,
|
||||
@@ -222,7 +222,7 @@ impl Mint {
|
||||
async fn get_melt_bolt12_quote_impl(
|
||||
&self,
|
||||
melt_request: &MeltQuoteBolt12Request,
|
||||
) -> Result<MeltQuoteBolt11Response<Uuid>, Error> {
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
let MeltQuoteBolt12Request {
|
||||
request,
|
||||
unit,
|
||||
@@ -322,8 +322,8 @@ impl Mint {
|
||||
#[instrument(skip(self))]
|
||||
pub async fn check_melt_quote(
|
||||
&self,
|
||||
quote_id: &Uuid,
|
||||
) -> Result<MeltQuoteBolt11Response<Uuid>, Error> {
|
||||
quote_id: &QuoteId,
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
let quote = self
|
||||
.localstore
|
||||
.get_melt_quote(quote_id)
|
||||
@@ -363,7 +363,7 @@ impl Mint {
|
||||
pub async fn check_melt_expected_ln_fees(
|
||||
&self,
|
||||
melt_quote: &MeltQuote,
|
||||
melt_request: &MeltRequest<Uuid>,
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
) -> Result<Option<Amount>, Error> {
|
||||
let quote_msats = to_unit(melt_quote.amount, &melt_quote.unit, &CurrencyUnit::Msat)
|
||||
.expect("Quote unit is checked above that it can convert to msat");
|
||||
@@ -445,7 +445,7 @@ impl Mint {
|
||||
&self,
|
||||
tx: &mut Box<dyn MintTransaction<'_, database::Error> + Send + Sync + '_>,
|
||||
input_verification: Verification,
|
||||
melt_request: &MeltRequest<Uuid>,
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
) -> Result<(ProofWriter, MeltQuote), Error> {
|
||||
let (state, quote) = tx
|
||||
.update_melt_quote_state(melt_request.quote(), MeltQuoteState::Pending, None)
|
||||
@@ -518,8 +518,8 @@ impl Mint {
|
||||
#[instrument(skip_all)]
|
||||
pub async fn melt(
|
||||
&self,
|
||||
melt_request: &MeltRequest<Uuid>,
|
||||
) -> Result<MeltQuoteBolt11Response<Uuid>, Error> {
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
use std::sync::Arc;
|
||||
async fn check_payment_state(
|
||||
ln: Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
||||
@@ -743,10 +743,10 @@ impl Mint {
|
||||
mut tx: Box<dyn MintTransaction<'_, database::Error> + Send + Sync + '_>,
|
||||
mut proof_writer: ProofWriter,
|
||||
quote: MeltQuote,
|
||||
melt_request: &MeltRequest<Uuid>,
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
payment_preimage: Option<String>,
|
||||
total_spent: Amount,
|
||||
) -> Result<MeltQuoteBolt11Response<Uuid>, Error> {
|
||||
) -> Result<MeltQuoteBolt11Response<QuoteId>, Error> {
|
||||
let input_ys = melt_request.inputs().ys()?;
|
||||
|
||||
proof_writer
|
||||
@@ -823,7 +823,7 @@ impl Mint {
|
||||
.map(|o| o.blinded_secret)
|
||||
.collect::<Vec<PublicKey>>(),
|
||||
&change_sigs,
|
||||
Some(quote.id),
|
||||
Some(quote.id.clone()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use cdk_common::database::MintAuthDatabase;
|
||||
use cdk_common::database::{self, MintDatabase, MintTransaction};
|
||||
use cdk_common::nuts::{self, BlindSignature, BlindedMessage, CurrencyUnit, Id, Kind};
|
||||
use cdk_common::payment::WaitPaymentResponse;
|
||||
pub use cdk_common::quote_id::QuoteId;
|
||||
use cdk_common::secret;
|
||||
use cdk_signatory::signatory::{Signatory, SignatoryKeySet};
|
||||
use futures::StreamExt;
|
||||
@@ -21,7 +22,6 @@ use subscription::PubSubManager;
|
||||
use tokio::sync::{Mutex, Notify};
|
||||
use tokio::task::{JoinHandle, JoinSet};
|
||||
use tracing::instrument;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::cdk_payment::{self, MintPayment};
|
||||
use crate::error::Error;
|
||||
@@ -758,7 +758,7 @@ impl Mint {
|
||||
&self,
|
||||
tx: &mut Box<dyn MintTransaction<'_, cdk_database::Error> + Send + Sync + '_>,
|
||||
melt_quote: &MeltQuote,
|
||||
melt_request: &MeltRequest<Uuid>,
|
||||
melt_request: &MeltRequest<QuoteId>,
|
||||
) -> Result<Option<Amount>, Error> {
|
||||
let mint_quote = match tx
|
||||
.get_mint_quote_by_request(&melt_quote.request.to_string())
|
||||
|
||||
@@ -5,8 +5,8 @@ use std::sync::Arc;
|
||||
use cdk_common::database::{self, MintDatabase};
|
||||
use cdk_common::mint::MintQuote;
|
||||
use cdk_common::nut17::Notification;
|
||||
use cdk_common::quote_id::QuoteId;
|
||||
use cdk_common::{Amount, MintQuoteBolt12Response, NotificationPayload, PaymentMethod};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::OnSubscription;
|
||||
use crate::nuts::{
|
||||
@@ -20,7 +20,9 @@ use crate::pub_sub;
|
||||
///
|
||||
/// Nut-17 implementation is system-wide and not only through the WebSocket, so
|
||||
/// it is possible for another part of the system to subscribe to events.
|
||||
pub struct PubSubManager(pub_sub::Manager<NotificationPayload<Uuid>, Notification, OnSubscription>);
|
||||
pub struct PubSubManager(
|
||||
pub_sub::Manager<NotificationPayload<QuoteId>, Notification, OnSubscription>,
|
||||
);
|
||||
|
||||
#[allow(clippy::default_constructed_unit_structs)]
|
||||
impl Default for PubSubManager {
|
||||
@@ -36,7 +38,7 @@ impl From<Arc<dyn MintDatabase<database::Error> + Send + Sync>> for PubSubManage
|
||||
}
|
||||
|
||||
impl Deref for PubSubManager {
|
||||
type Target = pub_sub::Manager<NotificationPayload<Uuid>, Notification, OnSubscription>;
|
||||
type Target = pub_sub::Manager<NotificationPayload<QuoteId>, Notification, OnSubscription>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
@@ -88,7 +90,7 @@ impl PubSubManager {
|
||||
}
|
||||
|
||||
/// Helper function to emit a MintQuoteBolt11Response status
|
||||
pub fn mint_quote_bolt11_status<E: Into<MintQuoteBolt11Response<Uuid>>>(
|
||||
pub fn mint_quote_bolt11_status<E: Into<MintQuoteBolt11Response<QuoteId>>>(
|
||||
&self,
|
||||
quote: E,
|
||||
new_state: MintQuoteState,
|
||||
@@ -100,7 +102,7 @@ impl PubSubManager {
|
||||
}
|
||||
|
||||
/// Helper function to emit a MintQuoteBolt11Response status
|
||||
pub fn mint_quote_bolt12_status<E: TryInto<MintQuoteBolt12Response<Uuid>>>(
|
||||
pub fn mint_quote_bolt12_status<E: TryInto<MintQuoteBolt12Response<QuoteId>>>(
|
||||
&self,
|
||||
quote: E,
|
||||
amount_paid: Amount,
|
||||
@@ -117,7 +119,7 @@ impl PubSubManager {
|
||||
}
|
||||
|
||||
/// Helper function to emit a MeltQuoteBolt11Response status
|
||||
pub fn melt_quote_status<E: Into<MeltQuoteBolt11Response<Uuid>>>(
|
||||
pub fn melt_quote_status<E: Into<MeltQuoteBolt11Response<QuoteId>>>(
|
||||
&self,
|
||||
quote: E,
|
||||
payment_preimage: Option<String>,
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::sync::Arc;
|
||||
use cdk_common::database::{self, MintDatabase};
|
||||
use cdk_common::nut17::Notification;
|
||||
use cdk_common::pub_sub::OnNewSubscription;
|
||||
use cdk_common::quote_id::QuoteId;
|
||||
use cdk_common::{MintQuoteBolt12Response, NotificationPayload, PaymentMethod};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::nuts::{MeltQuoteBolt11Response, MintQuoteBolt11Response, ProofState, PublicKey};
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct OnSubscription(pub(crate) Option<Arc<dyn MintDatabase<database::Error
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl OnNewSubscription for OnSubscription {
|
||||
type Event = NotificationPayload<Uuid>;
|
||||
type Event = NotificationPayload<QuoteId>;
|
||||
type Index = Notification;
|
||||
|
||||
async fn on_new_subscription(
|
||||
@@ -65,7 +65,7 @@ impl OnNewSubscription for OnSubscription {
|
||||
quotes
|
||||
.into_iter()
|
||||
.filter_map(|quote| quote.map(|x| x.into()))
|
||||
.map(|x: MeltQuoteBolt11Response<Uuid>| x.into())
|
||||
.map(|x: MeltQuoteBolt11Response<QuoteId>| x.into())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.map_err(|e| e.to_string())?,
|
||||
@@ -82,12 +82,13 @@ impl OnNewSubscription for OnSubscription {
|
||||
.filter_map(|quote| {
|
||||
quote.and_then(|x| match x.payment_method {
|
||||
PaymentMethod::Bolt11 => {
|
||||
let response: MintQuoteBolt11Response<Uuid> = x.into();
|
||||
let response: MintQuoteBolt11Response<QuoteId> = x.into();
|
||||
Some(response.into())
|
||||
}
|
||||
PaymentMethod::Bolt12 => match x.try_into() {
|
||||
Ok(response) => {
|
||||
let response: MintQuoteBolt12Response<Uuid> = response;
|
||||
let response: MintQuoteBolt12Response<QuoteId> =
|
||||
response;
|
||||
Some(response.into())
|
||||
}
|
||||
Err(_) => None,
|
||||
|
||||
Reference in New Issue
Block a user