From d4ca37ed7b66318fd3030e404acc63866b849ec4 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Tue, 5 Dec 2023 15:30:12 +0100 Subject: [PATCH] feat: store quote for melt in db --- moksha-core/src/primitives.rs | 2 + moksha-mint/src/database.rs | 11 ++- moksha-mint/src/mint.rs | 6 +- moksha-mint/src/model.rs | 39 ++++++---- moksha-mint/src/server.rs | 131 ++++++++++++++++++++++++---------- 5 files changed, 135 insertions(+), 54 deletions(-) diff --git a/moksha-core/src/primitives.rs b/moksha-core/src/primitives.rs index f44c9773..819b2c95 100644 --- a/moksha-core/src/primitives.rs +++ b/moksha-core/src/primitives.rs @@ -158,6 +158,8 @@ pub struct PostMeltQuoteBolt11Response { pub quote: String, pub amount: u64, pub fee_reserve: u64, + pub paid: bool, + pub expiry: u64, } #[derive(Deserialize, Serialize, Debug, Clone)] diff --git a/moksha-mint/src/database.rs b/moksha-mint/src/database.rs index b38ebbc4..eefbb28d 100644 --- a/moksha-mint/src/database.rs +++ b/moksha-mint/src/database.rs @@ -264,9 +264,14 @@ mod tests { let tmp_dir = tmp.path().to_str().expect("Could not create tmp dir"); let db = super::RocksDB::new(tmp_dir.to_owned()); - let quote = Quote::new(Uuid::new_v4(), "12345678".to_owned()); - let key = quote.quote_id.to_string(); - db.add_quote(key.clone(), quote.clone())?; + let key = Uuid::new_v4(); + let quote = Quote::Bolt11Mint { + quote_id: key, + payment_request: "12345678".to_owned(), + expiry: 12345678, + }; + + db.add_quote(key.to_string(), quote.clone())?; let lookup_quote = db.get_quote(key.to_string())?; assert_eq!(quote, lookup_quote); diff --git a/moksha-mint/src/mint.rs b/moksha-mint/src/mint.rs index d59f69f3..aedcefc7 100644 --- a/moksha-mint/src/mint.rs +++ b/moksha-mint/src/mint.rs @@ -115,10 +115,10 @@ impl Mint { pub async fn mint_tokens( &self, - invoice_hash: String, + key: String, outputs: &[BlindedMessage], ) -> Result, MokshaMintError> { - let invoice = self.db.get_pending_invoice(invoice_hash.clone())?; + let invoice = self.db.get_pending_invoice(key.clone())?; let is_paid = self .lightning @@ -129,7 +129,7 @@ impl Mint { return Err(MokshaMintError::InvoiceNotPaidYet); } - self.db.remove_pending_invoice(invoice_hash)?; + self.db.remove_pending_invoice(key)?; self.create_blinded_signatures(outputs) } diff --git a/moksha-mint/src/model.rs b/moksha-mint/src/model.rs index 97f20087..35210b1a 100644 --- a/moksha-mint/src/model.rs +++ b/moksha-mint/src/model.rs @@ -47,17 +47,32 @@ pub struct CreateInvoiceParams { pub internal: Option, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct Quote { - pub quote_id: Uuid, - pub payment_request: String, -} +// #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +// pub struct Quote { +// pub quote_id: Uuid, +// pub payment_request: String, +// } -impl Quote { - pub fn new(quote_id: Uuid, payment_request: String) -> Self { - Self { - quote_id, - payment_request, - } - } +// impl Quote { +// pub fn new(quote_id: Uuid, payment_request: String) -> Self { +// Self { +// quote_id, +// payment_request, +// } +// } +// } + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum Quote { + Bolt11Mint { + quote_id: Uuid, + payment_request: String, + expiry: u64, + }, + Bolt11Melt { + quote_id: Uuid, + amount: u64, + fee_reserve: u64, + expiry: u64, + }, } diff --git a/moksha-mint/src/server.rs b/moksha-mint/src/server.rs index 6dc94f01..ae049cc9 100644 --- a/moksha-mint/src/server.rs +++ b/moksha-mint/src/server.rs @@ -86,9 +86,10 @@ fn app(mint: Mint, serve_wallet_path: Option, prefix: Option) - .route("/v1/keys", get(get_keys)) .route("/v1/keysets", get(get_keysets)) .route("/v1/mint/quote/bolt11", post(post_mint_quote_bolt11)) - .route("/v1/mint/quote/bolt11/:quote_id", get(get_mint_quote)) + .route("/v1/mint/quote/bolt11/:quote", get(get_mint_quote_bolt11)) .route("/v1/mint/bolt11", post(post_mint_bolt11)) .route("/v1/melt/quote/bolt11", post(post_melt_quote_bolt11)) + .route("/v1/melt/quote/bolt11/:quote", get(get_melt_quote_bolt11)) .route("/v1/melt/bolt11", post(post_melt_bolt11)) .route("/v1/swap", post(post_split)) .route("/v1/info", get(get_legacy_info)); @@ -279,15 +280,20 @@ async fn post_mint_quote_bolt11( let (pr, _hash) = mint.create_invoice(key.to_string(), request.amount).await?; let invoice = mint.lightning.decode_invoice(pr.clone()).await?; - let quote = Quote::new(key, pr.clone()); - let quote_id = quote.quote_id.to_string(); - mint.db.add_quote(quote_id.clone(), quote)?; + let expiry = invoice.expiry_time().as_secs(); + let quote = Quote::Bolt11Mint { + quote_id: key, + payment_request: pr.clone(), + expiry, // FIXME check if this is correct + }; + + mint.db.add_quote(key.to_string(), quote)?; Ok(Json(PostMintQuoteBolt11Response { - quote: quote_id, + quote: key.to_string(), request: pr, paid: false, - expiry: invoice.expiry_time().as_secs(), // FIXME check if this is correct + expiry, })) } @@ -300,10 +306,15 @@ async fn post_mint_bolt11( .get(request.quote.as_str()) .ok_or_else(|| crate::error::MokshaMintError::InvalidQuote(request.quote.clone()))?; - let signatures = mint - .mint_tokens(quote.quote_id.to_string(), &request.outputs) - .await?; - Ok(Json(PostMintBolt11Response { signatures })) + match quote { + Quote::Bolt11Mint { .. } => { + let signatures = mint.mint_tokens(request.quote, &request.outputs).await?; + Ok(Json(PostMintBolt11Response { signatures })) + } + _ => Err(crate::error::MokshaMintError::InvalidQuote( + request.quote.clone(), + )), + } } async fn post_melt_quote_bolt11( @@ -319,10 +330,23 @@ async fn post_melt_quote_bolt11( .ok_or_else(|| crate::error::MokshaMintError::InvalidAmount)?; let fee_reserve = mint.fee_reserve(amount); + // Store quote in db + let key = Uuid::new_v4(); + let quote = Quote::Bolt11Melt { + quote_id: key, + amount, + fee_reserve, + expiry: invoice.expiry_time().as_secs(), // FIXME check if this is correct + }; + mint.db.add_quote(key.to_string(), quote)?; + + // TODO implement into for Quote Ok(Json(PostMeltQuoteBolt11Response { amount, fee_reserve, quote: melt_request.request.clone(), // FIXME use uuid as quote + paid: false, + expiry: invoice.expiry_time().as_secs(), // FIXME check if this is correct })) } @@ -330,42 +354,77 @@ async fn post_melt_bolt11( State(mint): State, Json(melt_request): Json, ) -> Result, MokshaMintError> { - let quote = mint.db.get_quote(melt_request.quote)?; - - let (paid, preimage, _change) = mint - .melt(quote.payment_request, &melt_request.inputs, &[]) - .await?; - - Ok(Json(PostMeltBolt11Response { - paid, - payment_preimage: preimage, - change: vec![], // FIXME return change - })) + let quote = mint.db.get_quote(melt_request.quote.clone())?; + + match quote { + Quote::Bolt11Melt { .. } => { + let (paid, preimage, change) = mint + .melt(melt_request.quote, &melt_request.inputs, &[]) + .await?; + + Ok(Json(PostMeltBolt11Response { + paid, + payment_preimage: preimage, + change, + })) + } + _ => Err(crate::error::MokshaMintError::InvalidQuote( + melt_request.quote.clone(), + )), + } } -async fn get_mint_quote( +async fn get_mint_quote_bolt11( Path(quote_id): Path, State(mint): State, ) -> Result, MokshaMintError> { info!("get_quote: {}", quote_id); let quote = mint.db.get_quote(quote_id.clone())?; - let invoice = mint - .lightning - .decode_invoice(quote.payment_request.clone()) - .await?; + match quote { + Quote::Bolt11Mint { + quote_id, + payment_request, + expiry, + } => { + let paid = mint + .lightning + .is_invoice_paid(payment_request.clone()) + .await?; + + Ok(Json(PostMintQuoteBolt11Response { + quote: quote_id.to_string(), + request: payment_request, + paid, + expiry, + })) + } + _ => Err(crate::error::MokshaMintError::InvalidQuote(quote_id)), + } +} - let is_paid = mint - .lightning - .is_invoice_paid(quote.payment_request.clone()) - .await?; +async fn get_melt_quote_bolt11( + Path(quote_id): Path, + State(mint): State, +) -> Result, MokshaMintError> { + info!("get_melt_quote: {}", quote_id); + let quote = mint.db.get_quote(quote_id.clone())?; - Ok(Json(PostMintQuoteBolt11Response { - quote: quote_id, - request: quote.payment_request, - paid: is_paid, - expiry: invoice.expiry_time().as_secs(), // FIXME check if this is correct - })) + match quote { + Quote::Bolt11Melt { + quote_id, + amount, + fee_reserve, + expiry, + } => Ok(Json(PostMeltQuoteBolt11Response { + amount, + fee_reserve, + quote: quote_id.to_string(), + paid: false, // FIXME check if paid + expiry, + })), + _ => Err(crate::error::MokshaMintError::InvalidQuote(quote_id)), + } } #[cfg(test)]