diff --git a/.env.example b/.env.example index 875b7e4a..c810cb8d 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,9 @@ # if set to 'dev' env variables from the .env file will be used MINT_APP_ENV=dev +# connection string for the postgres database MINT_DB_URL=postgres://postgres:postgres@127.0.0.1/moksha-mint +# the private key of the mint MINT_PRIVATE_KEY=superprivatesecretkey # the host and port the mint will listen on int the format https://doc.rust-lang.org/std/net/enum.SocketAddr.html @@ -16,6 +18,7 @@ MINT_API_PREFIX=/api # if set will serve the wallet from the given path #MINT_SERVE_WALLET_PATH=./flutter/build/web +# optional mint info MINT_INFO_NAME=moksha-mint # If set to true the version of the mint crate will be displayed in the mint info MINT_INFO_VERSION=true diff --git a/docker-compose.yml b/docker-compose.yml index 3cd78b91..36183b51 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: POSTGRES_DB: moksha-mint app: image: "docker.io/ngutech21/moksha-mint:latest" - #image: "moksha-mint:latest" + #image: "moksha-mint:latest" # for local testing ports: - 3338:3338 volumes: diff --git a/moksha-mint/src/bin/moksha-mint.rs b/moksha-mint/src/bin/moksha-mint.rs index abe3e803..0fe49fa5 100644 --- a/moksha-mint/src/bin/moksha-mint.rs +++ b/moksha-mint/src/bin/moksha-mint.rs @@ -1,10 +1,10 @@ use mokshamint::{ - info::MintInfoSettings, + config::{LightningFeeConfig, MintInfoConfig}, lightning::{ AlbyLightningSettings, LightningType, LnbitsLightningSettings, LndLightningSettings, StrikeLightningSettings, }, - mint::{LightningFeeConfig, MintBuilder}, + mint::MintBuilder, }; use std::{env, fmt, net::SocketAddr, path::PathBuf}; @@ -62,18 +62,10 @@ pub async fn main() -> anyhow::Result<()> { }; let mint_info_settings = envy::prefixed("MINT_INFO_") - .from_env::() + .from_env::() .expect("Please provide mint info"); - let fee_config_default = LightningFeeConfig::default(); - - let fee_config = LightningFeeConfig { - fee_percent: env_or_default("LIGHTNING_FEE_PERCENT", fee_config_default.fee_percent), - fee_reserve_min: env_or_default( - "LIGHTNING_RESERVE_FEE_MIN", - fee_config_default.fee_reserve_min, - ), - }; + let fee_config = LightningFeeConfig::from_env(); let mint = MintBuilder::new() .with_mint_info(mint_info_settings) @@ -93,13 +85,6 @@ pub async fn main() -> anyhow::Result<()> { mokshamint::server::run_server(mint?, host_port, serve_wallet_path, api_prefix).await } -fn env_or_default(key: &str, default: T) -> T { - env::var(key) - .ok() - .and_then(|v| v.parse().ok()) - .unwrap_or(default) -} - #[derive(Debug, PartialEq)] pub enum AppEnv { Dev, diff --git a/moksha-mint/src/config.rs b/moksha-mint/src/config.rs new file mode 100644 index 00000000..34cde103 --- /dev/null +++ b/moksha-mint/src/config.rs @@ -0,0 +1,90 @@ +use std::env; + +use serde_derive::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug, Clone, Default)] +pub struct MintInfoConfig { + pub name: Option, + #[serde(default = "default_version")] + pub version: bool, + pub description: Option, + pub description_long: Option, + pub contact: Option>>, + pub motd: Option, + // FIXME add missing fields for v1/info endpoint nut4/nut5 payment_methods, nut4 disabled flag +} + +fn default_version() -> bool { + true +} + +#[derive(Deserialize, Serialize, Debug, Clone, Default)] +pub struct BuildConfig { + pub commit_hash: Option, + pub build_time: Option, + pub cargo_pkg_version: Option, +} + +impl BuildConfig { + pub fn from_env() -> Self { + Self { + commit_hash: env::var("COMMITHASH").ok().map(|s| s.to_string()), + build_time: env::var("BUILDTIME").ok().map(|s| s.to_string()), + cargo_pkg_version: Some(env!("CARGO_PKG_VERSION").to_owned()), + } + } + + pub fn full_version(&self) -> String { + format!( + "{}-{}", + self.cargo_pkg_version + .as_ref() + .unwrap_or(&"unknown".to_string()), + self.commit_hash.as_ref().unwrap_or(&"unknown".to_string()) + ) + } +} + +#[derive(Clone, Debug)] +pub struct LightningFeeConfig { + pub fee_percent: f32, + pub fee_reserve_min: u64, + // TODO check if fee_percent is in range +} + +impl LightningFeeConfig { + pub fn new(fee_percent: f32, fee_reserve_min: u64) -> Self { + Self { + fee_percent, + fee_reserve_min, + } + } + + pub fn from_env() -> Self { + let fee_config_default = LightningFeeConfig::default(); + + LightningFeeConfig { + fee_percent: env_or_default("LIGHTNING_FEE_PERCENT", fee_config_default.fee_percent), + fee_reserve_min: env_or_default( + "LIGHTNING_RESERVE_FEE_MIN", + fee_config_default.fee_reserve_min, + ), + } + } +} + +fn env_or_default(key: &str, default: T) -> T { + env::var(key) + .ok() + .and_then(|v| v.parse().ok()) + .unwrap_or(default) +} + +impl Default for LightningFeeConfig { + fn default() -> Self { + Self { + fee_percent: 1.0, + fee_reserve_min: 4000, + } + } +} diff --git a/moksha-mint/src/info.rs b/moksha-mint/src/info.rs deleted file mode 100644 index b40b696d..00000000 --- a/moksha-mint/src/info.rs +++ /dev/null @@ -1,12 +0,0 @@ -use serde_derive::{Deserialize, Serialize}; - -#[derive(Deserialize, Serialize, Debug, Clone, Default)] -pub struct MintInfoSettings { - pub name: Option, - #[serde(default)] - pub version: bool, - pub description: Option, - pub description_long: Option, - pub contact: Option>>, - pub motd: Option, -} diff --git a/moksha-mint/src/lib.rs b/moksha-mint/src/lib.rs index 21b53fff..67ef405c 100644 --- a/moksha-mint/src/lib.rs +++ b/moksha-mint/src/lib.rs @@ -1,6 +1,6 @@ +pub mod config; pub mod database; pub mod error; -pub mod info; pub mod lightning; pub mod mint; pub mod model; diff --git a/moksha-mint/src/mint.rs b/moksha-mint/src/mint.rs index c50e8b46..e808d12f 100644 --- a/moksha-mint/src/mint.rs +++ b/moksha-mint/src/mint.rs @@ -8,9 +8,9 @@ use moksha_core::{ }; use crate::{ + config::{BuildConfig, LightningFeeConfig, MintInfoConfig}, database::Database, error::MokshaMintError, - info::MintInfoSettings, lightning::{AlbyLightning, Lightning, LightningType, LnbitsLightning, StrikeLightning}, model::Invoice, }; @@ -25,35 +25,12 @@ pub struct Mint { pub db: Arc, pub dhke: Dhke, pub lightning_fee_config: LightningFeeConfig, - pub mint_info: MintInfoSettings, // FIXME use new mint info instead of legacy -} - -#[derive(Clone, Debug)] -pub struct LightningFeeConfig { - pub fee_percent: f32, - pub fee_reserve_min: u64, - // TODO check if fee_percent is in range -} - -impl LightningFeeConfig { - pub fn new(fee_percent: f32, fee_reserve_min: u64) -> Self { - Self { - fee_percent, - fee_reserve_min, - } - } -} - -impl Default for LightningFeeConfig { - fn default() -> Self { - Self { - fee_percent: 1.0, - fee_reserve_min: 4000, - } - } + pub mint_info_config: MintInfoConfig, + pub build_config: BuildConfig, } impl Mint { + // FIXME create a new struct for all config-settings pub fn new( secret: String, derivation_path: String, @@ -61,7 +38,8 @@ impl Mint { lightning_type: LightningType, db: Arc, lightning_fee_config: LightningFeeConfig, - mint_info: MintInfoSettings, + mint_info_config: MintInfoConfig, + build_config: BuildConfig, ) -> Self { Self { lightning, @@ -71,7 +49,8 @@ impl Mint { keyset: MintKeyset::new(&secret, &derivation_path), db, dhke: Dhke::new(), - mint_info, + mint_info_config, + build_config, } } @@ -228,7 +207,7 @@ pub struct MintBuilder { lightning_type: Option, db_url: Option, fee_config: Option, - mint_info_settings: Option, + mint_info_settings: Option, } impl MintBuilder { @@ -236,7 +215,7 @@ impl MintBuilder { Self::default() } - pub fn with_mint_info(mut self, mint_info: MintInfoSettings) -> MintBuilder { + pub fn with_mint_info(mut self, mint_info: MintInfoConfig) -> MintBuilder { self.mint_info_settings = Some(mint_info); self } @@ -304,6 +283,7 @@ impl MintBuilder { db, self.fee_config.expect("fee-config not set"), self.mint_info_settings.unwrap_or_default(), + BuildConfig::from_env(), )) } } @@ -457,6 +437,7 @@ mod tests { Arc::new(create_mock_db_get_used_proofs()), Default::default(), Default::default(), + Default::default(), ); let tokens = create_token_from_fixture("token_60.cashu".to_string())?; @@ -516,6 +497,7 @@ mod tests { db, Default::default(), Default::default(), + Default::default(), ) } diff --git a/moksha-mint/src/server.rs b/moksha-mint/src/server.rs index 01c8bd80..413850fd 100644 --- a/moksha-mint/src/server.rs +++ b/moksha-mint/src/server.rs @@ -56,17 +56,17 @@ pub async fn run_server( .with(tracing_subscriber::fmt::layer()) .init(); - if let Ok(buildtime) = std::env::var("BUILDTIME") { + if let Some(ref buildtime) = mint.build_config.build_time { info!("build time: {}", buildtime); } - if let Ok(commithash) = std::env::var("COMMITHASH") { + if let Some(ref commithash) = mint.build_config.commit_hash { info!("git commit-hash: {}", commithash); } if let Some(ref serve_wallet_path) = serve_wallet_path { info!("serving wallet from path: {:?}", serve_wallet_path); } info!("listening on: {}", addr); - info!("mint-info (legacy): {:?}", mint.mint_info); + info!("mint-info (legacy): {:?}", mint.mint_info_config); info!("lightning fee-reserve: {:?}", mint.lightning_fee_config); info!("lightning-backend: {}", mint.lightning_type); @@ -273,15 +273,15 @@ async fn get_legacy_info( State(mint): State, ) -> Result, MokshaMintError> { let mint_info = MintLegacyInfoResponse { - name: mint.mint_info.name, + name: mint.mint_info_config.name, pubkey: mint.keyset_legacy.mint_pubkey, - version: match mint.mint_info.version { - true => Some(env!("CARGO_PKG_VERSION").to_owned()), + version: match mint.mint_info_config.version { + true => Some(mint.build_config.full_version()), _ => None, }, - description: mint.mint_info.description, - description_long: mint.mint_info.description_long, - contact: mint.mint_info.contact, + description: mint.mint_info_config.description, + description_long: mint.mint_info_config.description_long, + contact: mint.mint_info_config.contact, nuts: vec![ "NUT-00".to_string(), "NUT-01".to_string(), @@ -293,7 +293,7 @@ async fn get_legacy_info( "NUT-08".to_string(), "NUT-09".to_string(), ], - motd: mint.mint_info.motd, + motd: mint.mint_info_config.motd, parameter: Default::default(), }; Ok(Json(mint_info)) @@ -635,17 +635,17 @@ async fn get_melt_quote_bolt11( )] async fn get_info(State(mint): State) -> Result, MokshaMintError> { let mint_info = MintInfoResponse { - name: mint.mint_info.name, + name: mint.mint_info_config.name, pubkey: mint.keyset_legacy.mint_pubkey, - version: match mint.mint_info.version { - true => Some(env!("CARGO_PKG_VERSION").to_owned()), + version: match mint.mint_info_config.version { + true => Some(mint.build_config.full_version()), _ => None, }, - description: mint.mint_info.description, - description_long: mint.mint_info.description_long, - contact: mint.mint_info.contact, + description: mint.mint_info_config.description, + description_long: mint.mint_info_config.description_long, + contact: mint.mint_info_config.contact, nuts: Nuts::default(), - motd: mint.mint_info.motd, + motd: mint.mint_info_config.motd, }; Ok(Json(mint_info)) } @@ -654,7 +654,10 @@ async fn get_info(State(mint): State) -> Result, Mo mod tests { use std::{collections::HashMap, sync::Arc}; - use crate::server::app; + use crate::{ + config::{BuildConfig, LightningFeeConfig}, + server::app, + }; use axum::{ body::Body, http::{Request, StatusCode}, @@ -668,10 +671,10 @@ mod tests { use tower::ServiceExt; use crate::{ + config::MintInfoConfig, database::MockDatabase, - info::MintInfoSettings, lightning::{LightningType, MockLightning}, - mint::{LightningFeeConfig, Mint}, + mint::Mint, }; #[tokio::test] @@ -704,7 +707,7 @@ mod tests { #[tokio::test] async fn test_get_info() -> anyhow::Result<()> { - let mint_info_settings = MintInfoSettings { + let mint_info_settings = MintInfoConfig { name: Some("Bob's Cashu mint".to_string()), version: true, description: Some("A mint for testing".to_string()), @@ -730,7 +733,7 @@ mod tests { Ok(()) } - fn create_mock_mint(mint_info: MintInfoSettings) -> Mint { + fn create_mock_mint(mint_info: MintInfoConfig) -> Mint { let db = Arc::new(MockDatabase::new()); let lightning = Arc::new(MockLightning::new()); @@ -742,6 +745,7 @@ mod tests { db, LightningFeeConfig::default(), mint_info, + BuildConfig::default(), ) }