Skip to content

Commit

Permalink
feat: add new v1 /info endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ngutech21 committed Dec 9, 2023
1 parent 01afaa6 commit 32e2d4a
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 15 deletions.
138 changes: 134 additions & 4 deletions moksha-core/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub struct CashuErrorResponse {

#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct MintInfoResponse {
pub struct MintLegacyInfoResponse {
pub name: Option<String>,
pub pubkey: PublicKey,
pub version: Option<String>,
Expand Down Expand Up @@ -134,6 +134,12 @@ impl Display for CurrencyUnit {
}
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]
#[serde(rename_all = "lowercase")]
pub enum PaymentMethod {
Bolt11,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct PostMintQuoteBolt11Request {
pub amount: u64,
Expand Down Expand Up @@ -189,11 +195,89 @@ pub struct PostMeltBolt11Response {
pub change: Vec<BlindedSignature>,
}

#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct MintInfoResponse {
pub name: Option<String>,
pub pubkey: PublicKey,
pub version: Option<String>,
pub description: Option<String>,
pub description_long: Option<String>,
pub contact: Option<Vec<Vec<String>>>,
pub nuts: Vec<MintInfoNut>,
pub motd: Option<String>,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub enum MintInfoNut {
/// Cryptography and Models
#[serde(rename = "0")]
Nut0 { disabled: bool },

/// Mint public keys
#[serde(rename = "1")]
Nut1 { disabled: bool },

/// Keysets and keyset IDs
#[serde(rename = "2")]
Nut2 { disabled: bool },

/// Swapping tokens
#[serde(rename = "3")]
Nut3 { disabled: bool },

/// Minting tokens
#[serde(rename = "4")]
Nut4 {
methods: Vec<(PaymentMethod, CurrencyUnit)>,
disabled: bool,
},

/// Melting tokens
#[serde(rename = "5")]
Nut5 {
methods: Vec<(PaymentMethod, CurrencyUnit)>,
disabled: bool,
},

/// Mint info
#[serde(rename = "6")]
Nut6 { disabled: bool },

/// Token state check
#[serde(rename = "7")]
Nut7 { supported: bool },

/// Overpaid Lightning fees
#[serde(rename = "8")]
Nut8 { supported: bool },

/// Deterministic backup and restore
#[serde(rename = "9")]
Nut9 { supported: bool },

/// Spending conditions
#[serde(rename = "10")]
Nut10 { supported: bool },

/// Pay-To-Pubkey (P2PK)
#[serde(rename = "11")]
Nut11 { supported: bool },

/// DLEQ proofs
#[serde(rename = "12")]
Nut12 { supported: bool },
}

#[cfg(test)]
mod tests {

use crate::{
dhke::public_key_from_hex,
primitives::{KeyResponse, MintInfoResponse, Parameter, PostSwapResponse},
primitives::{
CurrencyUnit, KeyResponse, MintInfoNut, MintInfoResponse, MintLegacyInfoResponse,
Parameter, PaymentMethod, PostSwapResponse,
},
};

#[test]
Expand All @@ -217,8 +301,8 @@ mod tests {
}

#[test]
fn test_deserialize_mint_info() -> anyhow::Result<()> {
let mint_info = MintInfoResponse {
fn test_deserialize_legacy_mint_info() -> anyhow::Result<()> {
let mint_info = MintLegacyInfoResponse {
name: Some("Bob's Cashu mint".to_string()),
pubkey: public_key_from_hex(
"02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2",
Expand Down Expand Up @@ -247,4 +331,50 @@ mod tests {

Ok(())
}

#[test]
fn test_deserialize_mint_info() -> anyhow::Result<()> {
let mint_info = MintInfoResponse {
name: Some("Bob's Cashu mint".to_string()),
pubkey: public_key_from_hex(
"02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2",
),
version: Some("Nutshell/0.11.0".to_string()),
description: Some("The short mint description".to_string()),
description_long: Some("A description that can be a long piece of text.".to_string()),
contact: Some(vec![
vec!["email".to_string(), "[email protected]".to_string()],
vec!["twitter".to_string(), "@me".to_string()],
vec!["nostr".to_string(), "npub...".to_string()],
]),
nuts: vec![
MintInfoNut::Nut0 { disabled: false },
MintInfoNut::Nut1 { disabled: false },
MintInfoNut::Nut2 { disabled: false },
MintInfoNut::Nut3 { disabled: false },
MintInfoNut::Nut4 {
methods: vec![(PaymentMethod::Bolt11, CurrencyUnit::Sat)],
disabled: false,
},
MintInfoNut::Nut5 {
methods: vec![(PaymentMethod::Bolt11, CurrencyUnit::Sat)],
disabled: false,
},
MintInfoNut::Nut6 { disabled: false },
MintInfoNut::Nut7 { supported: false },
MintInfoNut::Nut8 { supported: false },
MintInfoNut::Nut9 { supported: false },
MintInfoNut::Nut10 { supported: false },
MintInfoNut::Nut11 { supported: false },
MintInfoNut::Nut12 { supported: false },
],
motd: Some("Message to display to users.".to_string()),
};
let out = serde_json::to_string_pretty(&mint_info)?;
println!("{}", out);
assert!(!out.is_empty());
// FIXME add asserts

Ok(())
}
}
59 changes: 48 additions & 11 deletions moksha-mint/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ use uuid::Uuid;
use crate::mint::Mint;
use crate::model::{GetMintQuery, PostMintQuery, Quote};
use moksha_core::primitives::{
CheckFeesRequest, CheckFeesResponse, CurrencyUnit, KeyResponse, KeysResponse, MintInfoResponse,
PaymentRequest, PostMeltBolt11Request, PostMeltBolt11Response, PostMeltQuoteBolt11Request,
PostMeltQuoteBolt11Response, PostMeltRequest, PostMeltResponse, PostMintBolt11Request,
PostMintBolt11Response, PostMintQuoteBolt11Request, PostMintQuoteBolt11Response,
PostMintRequest, PostMintResponse, PostSplitRequest, PostSplitResponse, PostSwapRequest,
PostSwapResponse,
CheckFeesRequest, CheckFeesResponse, CurrencyUnit, KeyResponse, KeysResponse, MintInfoNut,
MintInfoResponse, MintLegacyInfoResponse, PaymentMethod, PaymentRequest, PostMeltBolt11Request,
PostMeltBolt11Response, PostMeltQuoteBolt11Request, PostMeltQuoteBolt11Response,
PostMeltRequest, PostMeltResponse, PostMintBolt11Request, PostMintBolt11Response,
PostMintQuoteBolt11Request, PostMintQuoteBolt11Response, PostMintRequest, PostMintResponse,
PostSplitRequest, PostSplitResponse, PostSwapRequest, PostSwapResponse,
};
use secp256k1::PublicKey;

Expand Down Expand Up @@ -94,7 +94,7 @@ fn app(mint: Mint, serve_wallet_path: Option<PathBuf>, prefix: Option<String>) -
.route("/v1/melt/quote/bolt11/:quote", get(get_melt_quote_bolt11))
.route("/v1/melt/bolt11", post(post_melt_bolt11))
.route("/v1/swap", post(post_swap))
.route("/v1/info", get(get_legacy_info));
.route("/v1/info", get(get_info));

let prefix = prefix.unwrap_or_else(|| "".to_owned());

Expand Down Expand Up @@ -199,8 +199,8 @@ async fn post_legacy_check_fees(

async fn get_legacy_info(
State(mint): State<Mint>,
) -> Result<Json<MintInfoResponse>, MokshaMintError> {
let mint_info = MintInfoResponse {
) -> Result<Json<MintLegacyInfoResponse>, MokshaMintError> {
let mint_info = MintLegacyInfoResponse {
name: mint.mint_info.name,
pubkey: mint.keyset_legacy.mint_pubkey,
version: match mint.mint_info.version {
Expand Down Expand Up @@ -482,6 +482,43 @@ async fn get_melt_quote_bolt11(
}
}

async fn get_info(State(mint): State<Mint>) -> Result<Json<MintInfoResponse>, MokshaMintError> {
let mint_info = MintInfoResponse {
name: mint.mint_info.name,
pubkey: mint.keyset_legacy.mint_pubkey,
version: match mint.mint_info.version {
true => Some(env!("CARGO_PKG_VERSION").to_owned()),
_ => None,
},
description: mint.mint_info.description,
description_long: mint.mint_info.description_long,
contact: mint.mint_info.contact,
nuts: vec![
MintInfoNut::Nut0 { disabled: false },
MintInfoNut::Nut1 { disabled: false },
MintInfoNut::Nut2 { disabled: false },
MintInfoNut::Nut3 { disabled: false },
MintInfoNut::Nut4 {
methods: vec![(PaymentMethod::Bolt11, CurrencyUnit::Sat)],
disabled: false,
},
MintInfoNut::Nut5 {
methods: vec![(PaymentMethod::Bolt11, CurrencyUnit::Sat)],
disabled: false,
},
MintInfoNut::Nut6 { disabled: false },
MintInfoNut::Nut7 { supported: false },
MintInfoNut::Nut8 { supported: false },
MintInfoNut::Nut9 { supported: false },
MintInfoNut::Nut10 { supported: true },
MintInfoNut::Nut11 { supported: true },
MintInfoNut::Nut12 { supported: true },
],
motd: mint.mint_info.motd,
};
Ok(Json(mint_info))
}

#[cfg(test)]
mod tests {
use std::{collections::HashMap, sync::Arc};
Expand All @@ -494,7 +531,7 @@ mod tests {
use http_body_util::BodyExt;
use moksha_core::{
keyset::{Keysets, V1Keysets},
primitives::{CurrencyUnit, KeysResponse, MintInfoResponse},
primitives::{CurrencyUnit, KeysResponse, MintLegacyInfoResponse},
};
use secp256k1::PublicKey;
use tower::ServiceExt;
Expand Down Expand Up @@ -550,7 +587,7 @@ mod tests {

assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let info = serde_json::from_slice::<MintInfoResponse>(&body)?;
let info = serde_json::from_slice::<MintLegacyInfoResponse>(&body)?;
assert!(!info.parameter.peg_out_only);
assert_eq!(info.nuts.len(), 9);
assert_eq!(info.name, Some("Bob's Cashu mint".to_string()));
Expand Down

0 comments on commit 32e2d4a

Please sign in to comment.