diff --git a/moksha-core/src/primitives.rs b/moksha-core/src/primitives.rs index 590a12d1..5f16de25 100644 --- a/moksha-core/src/primitives.rs +++ b/moksha-core/src/primitives.rs @@ -261,7 +261,7 @@ pub struct BtcOnchainMintQuote { pub unit: CurrencyUnit, pub amount: u64, pub expiry: u64, - pub paid: bool, + pub state: MintBtcOnchainState, } impl From for PostMintQuoteBtcOnchainResponse { @@ -269,7 +269,7 @@ impl From for PostMintQuoteBtcOnchainResponse { Self { quote: quote.quote_id.to_string(), address: quote.address, - paid: quote.paid, + state: quote.state, expiry: quote.expiry, } } @@ -297,10 +297,48 @@ pub struct PostMintQuoteBtcOnchainRequest { pub struct PostMintQuoteBtcOnchainResponse { pub quote: String, pub address: String, - pub paid: bool, + pub state: MintBtcOnchainState, pub expiry: u64, } +#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, ToSchema)] +#[serde(rename_all = "UPPERCASE")] +pub enum MintBtcOnchainState { + /// initial state. No payment received from the wallet yet + Unpaid, + + Pending, + + Paid, + + Issued, +} + +impl Display for MintBtcOnchainState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MintBtcOnchainState::Unpaid => write!(f, "UNPAID"), + MintBtcOnchainState::Pending => write!(f, "PENDING"), + MintBtcOnchainState::Paid => write!(f, "PAID"), + MintBtcOnchainState::Issued => write!(f, "ISSUED"), + } + } +} + +impl FromStr for MintBtcOnchainState { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "UNPAID" => Ok(MintBtcOnchainState::Unpaid), + "PENDING" => Ok(MintBtcOnchainState::Pending), + "PAID" => Ok(MintBtcOnchainState::Paid), + "ISSUED" => Ok(MintBtcOnchainState::Issued), + _ => Err(()), + } + } +} + #[derive(Deserialize, Serialize, Debug, Clone, ToSchema)] pub struct PostMintBtcOnchainRequest { pub quote: String, diff --git a/moksha-mint/.sqlx/query-999dd087d936d0fe235a5cffa7c9ee71eb2c9d1035b738cc08804f434d3d7445.json b/moksha-mint/.sqlx/query-2cb95b0c3011a332322132339e6023035e4a81824bef6a0ad47215f851fb1100.json similarity index 65% rename from moksha-mint/.sqlx/query-999dd087d936d0fe235a5cffa7c9ee71eb2c9d1035b738cc08804f434d3d7445.json rename to moksha-mint/.sqlx/query-2cb95b0c3011a332322132339e6023035e4a81824bef6a0ad47215f851fb1100.json index 61494b2a..eacff7e7 100644 --- a/moksha-mint/.sqlx/query-999dd087d936d0fe235a5cffa7c9ee71eb2c9d1035b738cc08804f434d3d7445.json +++ b/moksha-mint/.sqlx/query-2cb95b0c3011a332322132339e6023035e4a81824bef6a0ad47215f851fb1100.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO onchain_mint_quotes (id, address, amount, expiry, paid) VALUES ($1, $2, $3, $4, $5)", + "query": "INSERT INTO onchain_mint_quotes (id, address, amount, expiry, state) VALUES ($1, $2, $3, $4, $5)", "describe": { "columns": [], "parameters": { @@ -9,10 +9,10 @@ "Text", "Int8", "Int8", - "Bool" + "Text" ] }, "nullable": [] }, - "hash": "999dd087d936d0fe235a5cffa7c9ee71eb2c9d1035b738cc08804f434d3d7445" + "hash": "2cb95b0c3011a332322132339e6023035e4a81824bef6a0ad47215f851fb1100" } diff --git a/moksha-mint/.sqlx/query-6d6efea17e2e8799c4e2e09c5eabf8e0e59da3646de7f1471b4507df7168ed32.json b/moksha-mint/.sqlx/query-6d6efea17e2e8799c4e2e09c5eabf8e0e59da3646de7f1471b4507df7168ed32.json new file mode 100644 index 00000000..2686b2cf --- /dev/null +++ b/moksha-mint/.sqlx/query-6d6efea17e2e8799c4e2e09c5eabf8e0e59da3646de7f1471b4507df7168ed32.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE onchain_mint_quotes SET state = $1 WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "6d6efea17e2e8799c4e2e09c5eabf8e0e59da3646de7f1471b4507df7168ed32" +} diff --git a/moksha-mint/.sqlx/query-9d30f87de843a27532d4222bcebfa6e01d09d8b7cea5cf49c1a8403404b2f91d.json b/moksha-mint/.sqlx/query-87908c797aa3343256255edb331044d890d22d06adc0313823dc8448e21e3f1c.json similarity index 73% rename from moksha-mint/.sqlx/query-9d30f87de843a27532d4222bcebfa6e01d09d8b7cea5cf49c1a8403404b2f91d.json rename to moksha-mint/.sqlx/query-87908c797aa3343256255edb331044d890d22d06adc0313823dc8448e21e3f1c.json index 8ef4f880..74a12255 100644 --- a/moksha-mint/.sqlx/query-9d30f87de843a27532d4222bcebfa6e01d09d8b7cea5cf49c1a8403404b2f91d.json +++ b/moksha-mint/.sqlx/query-87908c797aa3343256255edb331044d890d22d06adc0313823dc8448e21e3f1c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, address, amount, expiry, paid FROM onchain_mint_quotes WHERE id = $1", + "query": "SELECT id, address, amount, expiry, state FROM onchain_mint_quotes WHERE id = $1", "describe": { "columns": [ { @@ -25,8 +25,8 @@ }, { "ordinal": 4, - "name": "paid", - "type_info": "Bool" + "name": "state", + "type_info": "Text" } ], "parameters": { @@ -42,5 +42,5 @@ false ] }, - "hash": "9d30f87de843a27532d4222bcebfa6e01d09d8b7cea5cf49c1a8403404b2f91d" + "hash": "87908c797aa3343256255edb331044d890d22d06adc0313823dc8448e21e3f1c" } diff --git a/moksha-mint/.sqlx/query-c355619f3e7a684e1250933f4f80444b1a2535b8998deda34f84e4c4c5cd00d4.json b/moksha-mint/.sqlx/query-c355619f3e7a684e1250933f4f80444b1a2535b8998deda34f84e4c4c5cd00d4.json deleted file mode 100644 index 6e79ebf4..00000000 --- a/moksha-mint/.sqlx/query-c355619f3e7a684e1250933f4f80444b1a2535b8998deda34f84e4c4c5cd00d4.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE onchain_mint_quotes SET paid = $1 WHERE id = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bool", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "c355619f3e7a684e1250933f4f80444b1a2535b8998deda34f84e4c4c5cd00d4" -} diff --git a/moksha-mint/migrations/20240801124852_btconchain_mint_state.sql b/moksha-mint/migrations/20240801124852_btconchain_mint_state.sql new file mode 100644 index 00000000..12ba3591 --- /dev/null +++ b/moksha-mint/migrations/20240801124852_btconchain_mint_state.sql @@ -0,0 +1,15 @@ +-- Add migration script here +ALTER TABLE onchain_mint_quotes +ADD COLUMN state TEXT; + +UPDATE onchain_mint_quotes +SET state = CASE + WHEN paid = true THEN 'PAID' + WHEN paid = false THEN 'UNPAID' +END; + +ALTER TABLE onchain_mint_quotes +DROP COLUMN paid; + +ALTER TABLE onchain_mint_quotes +ALTER COLUMN state SET NOT NULL; \ No newline at end of file diff --git a/moksha-mint/src/database/postgres.rs b/moksha-mint/src/database/postgres.rs index bc34a32d..7d6f16bd 100644 --- a/moksha-mint/src/database/postgres.rs +++ b/moksha-mint/src/database/postgres.rs @@ -6,7 +6,7 @@ use moksha_core::{ dhke, primitives::{ Bolt11MeltQuote, Bolt11MintQuote, BtcOnchainMeltQuote, BtcOnchainMintQuote, CurrencyUnit, - MeltBtcOnchainState, + MeltBtcOnchainState, MintBtcOnchainState, }, proof::{Proof, Proofs}, }; @@ -295,14 +295,14 @@ impl Database for PostgresDB { key: &Uuid, ) -> Result { let quote: BtcOnchainMintQuote = sqlx::query!( - "SELECT id, address, amount, expiry, paid FROM onchain_mint_quotes WHERE id = $1", + "SELECT id, address, amount, expiry, state FROM onchain_mint_quotes WHERE id = $1", key ) .map(|row| BtcOnchainMintQuote { quote_id: row.id, address: row.address, expiry: row.expiry as u64, - paid: row.paid, + state: MintBtcOnchainState::from_str(&row.state).expect("invalid state in mint quote"), amount: row.amount as u64, unit: CurrencyUnit::Sat, }) @@ -319,12 +319,12 @@ impl Database for PostgresDB { quote: &BtcOnchainMintQuote, ) -> Result<(), MokshaMintError> { sqlx::query!( - "INSERT INTO onchain_mint_quotes (id, address, amount, expiry, paid) VALUES ($1, $2, $3, $4, $5)", + "INSERT INTO onchain_mint_quotes (id, address, amount, expiry, state) VALUES ($1, $2, $3, $4, $5)", quote.quote_id, quote.address, quote.amount as i64, quote.expiry as i64, - quote.paid, + quote.state.to_string(), ) .execute(&mut **tx) .await?; @@ -338,8 +338,8 @@ impl Database for PostgresDB { quote: &BtcOnchainMintQuote, ) -> Result<(), MokshaMintError> { sqlx::query!( - "UPDATE onchain_mint_quotes SET paid = $1 WHERE id = $2", - quote.paid, + "UPDATE onchain_mint_quotes SET state = $1 WHERE id = $2", + quote.state.to_string(), quote.quote_id ) .execute(&mut **tx) diff --git a/moksha-mint/src/routes/btconchain.rs b/moksha-mint/src/routes/btconchain.rs index 8ac14293..2686bb8f 100644 --- a/moksha-mint/src/routes/btconchain.rs +++ b/moksha-mint/src/routes/btconchain.rs @@ -3,10 +3,10 @@ use axum::{ Json, }; use moksha_core::primitives::{ - BtcOnchainMeltQuote, BtcOnchainMintQuote, CurrencyUnit, MeltBtcOnchainState, PaymentMethod, - PostMeltBtcOnchainRequest, PostMeltBtcOnchainResponse, PostMeltQuoteBtcOnchainRequest, - PostMeltQuoteBtcOnchainResponse, PostMintBtcOnchainRequest, PostMintBtcOnchainResponse, - PostMintQuoteBtcOnchainRequest, PostMintQuoteBtcOnchainResponse, + BtcOnchainMeltQuote, BtcOnchainMintQuote, CurrencyUnit, MeltBtcOnchainState, + MintBtcOnchainState, PaymentMethod, PostMeltBtcOnchainRequest, PostMeltBtcOnchainResponse, + PostMeltQuoteBtcOnchainRequest, PostMeltQuoteBtcOnchainResponse, PostMintBtcOnchainRequest, + PostMintBtcOnchainResponse, PostMintQuoteBtcOnchainRequest, PostMintQuoteBtcOnchainResponse, }; use tracing::{info, instrument}; use uuid::Uuid; @@ -63,7 +63,7 @@ pub async fn post_mint_quote_btconchain( unit: request.unit, amount: request.amount, expiry: quote_onchain_expiry(), - paid: false, + state: MintBtcOnchainState::Unpaid, }; let mut tx = mint.db.begin_tx().await?; @@ -109,7 +109,13 @@ pub async fn get_mint_quote_btconchain( .is_paid("e.address, quote.amount, min_confs) .await?; - Ok(Json(BtcOnchainMintQuote { paid, ..quote }.into())) + // FIXME compute correct state + let state = match paid { + true => MintBtcOnchainState::Paid, + false => MintBtcOnchainState::Unpaid, + }; + + Ok(Json(BtcOnchainMintQuote { state, ..quote }.into())) } #[utoipa::path( @@ -146,7 +152,7 @@ pub async fn post_mint_btconchain( .update_onchain_mint_quote( &mut tx, &BtcOnchainMintQuote { - paid: true, + state: MintBtcOnchainState::Issued, ..old_quote.clone() }, ) diff --git a/moksha-wallet/src/wallet.rs b/moksha-wallet/src/wallet.rs index 1d83ec3d..5f9ca992 100644 --- a/moksha-wallet/src/wallet.rs +++ b/moksha-wallet/src/wallet.rs @@ -4,9 +4,10 @@ use moksha_core::{ dhke::Dhke, keyset::KeysetId, primitives::{ - CurrencyUnit, MeltBtcOnchainState, MintInfoResponse, PaymentMethod, PostMeltBolt11Response, - PostMeltBtcOnchainResponse, PostMeltQuoteBolt11Response, PostMeltQuoteBtcOnchainResponse, - PostMintQuoteBolt11Response, PostMintQuoteBtcOnchainResponse, + CurrencyUnit, MeltBtcOnchainState, MintBtcOnchainState, MintInfoResponse, PaymentMethod, + PostMeltBolt11Response, PostMeltBtcOnchainResponse, PostMeltQuoteBolt11Response, + PostMeltQuoteBtcOnchainResponse, PostMintQuoteBolt11Response, + PostMintQuoteBtcOnchainResponse, }, proof::{Proof, Proofs}, token::TokenV3, @@ -160,10 +161,13 @@ where } PaymentMethod::BtcOnchain => { - self.client - .get_mint_quote_onchain(mint_url, quote) - .await? - .paid + matches!( + self.client + .get_mint_quote_onchain(mint_url, quote) + .await? + .state, + MintBtcOnchainState::Paid | MintBtcOnchainState::Issued + ) } }) }