feat: bolt12

This commit is contained in:
thesimplekid
2025-07-06 21:20:25 +01:00
parent 34e91dc924
commit ae6c107809
86 changed files with 6297 additions and 1934 deletions

View File

@@ -101,6 +101,9 @@ pub enum Error {
/// Invalid keyset ID
#[error("Invalid keyset ID")]
InvalidKeysetId,
/// Invalid melt payment request
#[error("Invalid melt payment request")]
InvalidMeltPaymentRequest,
}
impl From<Error> for cdk_common::database::Error {

View File

@@ -44,7 +44,7 @@ pub async fn new_with_state(
let mut tx = MintDatabase::begin_transaction(&db).await?;
for quote in mint_quotes {
tx.add_or_replace_mint_quote(quote).await?;
tx.add_mint_quote(quote).await?;
}
for quote in melt_quotes {

View File

@@ -21,4 +21,5 @@ pub static MIGRATIONS: &[(&str, &str)] = &[
("20250406093755_mint_created_time_signature.sql", include_str!(r#"./migrations/20250406093755_mint_created_time_signature.sql"#)),
("20250415093121_drop_keystore_foreign.sql", include_str!(r#"./migrations/20250415093121_drop_keystore_foreign.sql"#)),
("20250626120251_rename_blind_message_y_to_b.sql", include_str!(r#"./migrations/20250626120251_rename_blind_message_y_to_b.sql"#)),
("20250706101057_bolt12.sql", include_str!(r#"./migrations/20250706101057_bolt12.sql"#)),
];

View File

@@ -0,0 +1,81 @@
-- Add new columns to mint_quote table
ALTER TABLE mint_quote ADD COLUMN amount_paid INTEGER NOT NULL DEFAULT 0;
ALTER TABLE mint_quote ADD COLUMN amount_issued INTEGER NOT NULL DEFAULT 0;
ALTER TABLE mint_quote ADD COLUMN payment_method TEXT NOT NULL DEFAULT 'BOLT11';
ALTER TABLE mint_quote DROP COLUMN issued_time;
ALTER TABLE mint_quote DROP COLUMN paid_time;
-- Set amount_paid equal to amount for quotes with PAID or ISSUED state
UPDATE mint_quote SET amount_paid = amount WHERE state = 'PAID' OR state = 'ISSUED';
-- Set amount_issued equal to amount for quotes with ISSUED state
UPDATE mint_quote SET amount_issued = amount WHERE state = 'ISSUED';
DROP INDEX IF EXISTS mint_quote_state_index;
-- Remove the state column from mint_quote table
ALTER TABLE mint_quote DROP COLUMN state;
-- Remove NOT NULL constraint from amount column
CREATE TABLE mint_quote_temp (
id TEXT PRIMARY KEY,
amount INTEGER,
unit TEXT NOT NULL,
request TEXT NOT NULL,
expiry INTEGER NOT NULL,
request_lookup_id TEXT UNIQUE,
pubkey TEXT,
created_time INTEGER NOT NULL DEFAULT 0,
amount_paid INTEGER NOT NULL DEFAULT 0,
amount_issued INTEGER NOT NULL DEFAULT 0,
payment_method TEXT NOT NULL DEFAULT 'BOLT11'
);
INSERT INTO mint_quote_temp (id, amount, unit, request, expiry, request_lookup_id, pubkey, created_time, amount_paid, amount_issued, payment_method)
SELECT id, amount, unit, request, expiry, request_lookup_id, pubkey, created_time, amount_paid, amount_issued, payment_method
FROM mint_quote;
DROP TABLE mint_quote;
ALTER TABLE mint_quote_temp RENAME TO mint_quote;
ALTER TABLE mint_quote ADD COLUMN request_lookup_id_kind TEXT NOT NULL DEFAULT 'payment_hash';
CREATE INDEX IF NOT EXISTS idx_mint_quote_created_time ON mint_quote(created_time);
CREATE INDEX IF NOT EXISTS idx_mint_quote_expiry ON mint_quote(expiry);
CREATE INDEX IF NOT EXISTS idx_mint_quote_request_lookup_id ON mint_quote(request_lookup_id);
CREATE INDEX IF NOT EXISTS idx_mint_quote_request_lookup_id_and_kind ON mint_quote(request_lookup_id, request_lookup_id_kind);
-- Create mint_quote_payments table
CREATE TABLE mint_quote_payments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quote_id TEXT NOT NULL,
payment_id TEXT NOT NULL UNIQUE,
timestamp INTEGER NOT NULL,
amount INTEGER NOT NULL,
FOREIGN KEY (quote_id) REFERENCES mint_quote(id)
);
-- Create index on payment_id for faster lookups
CREATE INDEX idx_mint_quote_payments_payment_id ON mint_quote_payments(payment_id);
CREATE INDEX idx_mint_quote_payments_quote_id ON mint_quote_payments(quote_id);
-- Create mint_quote_issued table
CREATE TABLE mint_quote_issued (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quote_id TEXT NOT NULL,
amount INTEGER NOT NULL,
timestamp INTEGER NOT NULL,
FOREIGN KEY (quote_id) REFERENCES mint_quote(id)
);
-- Create index on quote_id for faster lookups
CREATE INDEX idx_mint_quote_issued_quote_id ON mint_quote_issued(quote_id);
-- Add new columns to melt_quote table
ALTER TABLE melt_quote ADD COLUMN payment_method TEXT NOT NULL DEFAULT 'bolt11';
ALTER TABLE melt_quote ADD COLUMN options TEXT;
ALTER TABLE melt_quote ADD COLUMN request_lookup_id_kind TEXT NOT NULL DEFAULT 'payment_hash';
CREATE INDEX IF NOT EXISTS idx_melt_quote_request_lookup_id_and_kind ON mint_quote(request_lookup_id, request_lookup_id_kind);
ALTER TABLE melt_quote DROP COLUMN msat_to_pay;

File diff suppressed because it is too large Load Diff

View File

@@ -17,4 +17,5 @@ pub static MIGRATIONS: &[(&str, &str)] = &[
("20250323152040_wallet_dleq_proofs.sql", include_str!(r#"./migrations/20250323152040_wallet_dleq_proofs.sql"#)),
("20250401120000_add_transactions_table.sql", include_str!(r#"./migrations/20250401120000_add_transactions_table.sql"#)),
("20250616144830_add_keyset_expiry.sql", include_str!(r#"./migrations/20250616144830_add_keyset_expiry.sql"#)),
("20250707093445_bolt12.sql", include_str!(r#"./migrations/20250707093445_bolt12.sql"#)),
];

View File

@@ -0,0 +1,58 @@
ALTER TABLE mint_quote ADD COLUMN amount_paid INTEGER NOT NULL DEFAULT 0;
ALTER TABLE mint_quote ADD COLUMN amount_minted INTEGER NOT NULL DEFAULT 0;
ALTER TABLE mint_quote ADD COLUMN payment_method TEXT NOT NULL DEFAULT 'BOLT11';
-- Remove NOT NULL constraint from amount column
PRAGMA foreign_keys=off;
CREATE TABLE mint_quote_new (
id TEXT PRIMARY KEY,
mint_url TEXT NOT NULL,
payment_method TEXT NOT NULL DEFAULT 'bolt11',
amount INTEGER,
unit TEXT NOT NULL,
request TEXT NOT NULL,
state TEXT NOT NULL,
expiry INTEGER NOT NULL,
amount_paid INTEGER NOT NULL DEFAULT 0,
amount_issued INTEGER NOT NULL DEFAULT 0,
secret_key TEXT
);
-- Explicitly specify columns for proper mapping
INSERT INTO mint_quote_new (
id,
mint_url,
payment_method,
amount,
unit,
request,
state,
expiry,
amount_paid,
amount_issued,
secret_key
)
SELECT
id,
mint_url,
'bolt11', -- Default value for the new payment_method column
amount,
unit,
request,
state,
expiry,
0, -- Default value for amount_paid
0, -- Default value for amount_minted
secret_key
FROM mint_quote;
DROP TABLE mint_quote;
ALTER TABLE mint_quote_new RENAME TO mint_quote;
PRAGMA foreign_keys=on;
-- Set amount_paid equal to amount for quotes with PAID or ISSUED state
UPDATE mint_quote SET amount_paid = amount WHERE state = 'PAID' OR state = 'ISSUED';
-- Set amount_issued equal to amount for quotes with ISSUED state
UPDATE mint_quote SET amount_issued = amount WHERE state = 'ISSUED';

View File

@@ -14,8 +14,8 @@ use cdk_common::nuts::{MeltQuoteState, MintQuoteState};
use cdk_common::secret::Secret;
use cdk_common::wallet::{self, MintQuote, Transaction, TransactionDirection, TransactionId};
use cdk_common::{
database, Amount, CurrencyUnit, Id, KeySet, KeySetInfo, Keys, MintInfo, Proof, ProofDleq,
PublicKey, SecretKey, SpendingConditions, State,
database, Amount, CurrencyUnit, Id, KeySet, KeySetInfo, Keys, MintInfo, PaymentMethod, Proof,
ProofDleq, PublicKey, SecretKey, SpendingConditions, State,
};
use error::Error;
use tracing::instrument;
@@ -376,9 +376,9 @@ ON CONFLICT(mint_url) DO UPDATE SET
Statement::new(
r#"
INSERT INTO mint_quote
(id, mint_url, amount, unit, request, state, expiry, secret_key)
(id, mint_url, amount, unit, request, state, expiry, secret_key, payment_method, amount_issued, amount_paid)
VALUES
(:id, :mint_url, :amount, :unit, :request, :state, :expiry, :secret_key)
(:id, :mint_url, :amount, :unit, :request, :state, :expiry, :secret_key, :payment_method, :amount_issued, :amount_paid)
ON CONFLICT(id) DO UPDATE SET
mint_url = excluded.mint_url,
amount = excluded.amount,
@@ -386,18 +386,24 @@ ON CONFLICT(id) DO UPDATE SET
request = excluded.request,
state = excluded.state,
expiry = excluded.expiry,
secret_key = excluded.secret_key
secret_key = excluded.secret_key,
payment_method = excluded.payment_method,
amount_issued = excluded.amount_issued,
amount_paid = excluded.amount_paid
;
"#,
)
.bind(":id", quote.id.to_string())
.bind(":mint_url", quote.mint_url.to_string())
.bind(":amount", u64::from(quote.amount) as i64)
.bind(":amount", quote.amount.map(|a| a.to_i64()))
.bind(":unit", quote.unit.to_string())
.bind(":request", quote.request)
.bind(":state", quote.state.to_string())
.bind(":expiry", quote.expiry as i64)
.bind(":secret_key", quote.secret_key.map(|p| p.to_string()))
.bind(":payment_method", quote.payment_method.to_string())
.bind(":amount_issued", quote.amount_issued.to_i64())
.bind(":amount_paid", quote.amount_paid.to_i64())
.execute(&self.pool.get().map_err(Error::Pool)?)
.map_err(Error::Sqlite)?;
@@ -416,7 +422,10 @@ ON CONFLICT(id) DO UPDATE SET
request,
state,
expiry,
secret_key
secret_key,
payment_method,
amount_issued,
amount_paid
FROM
mint_quote
WHERE
@@ -950,16 +959,24 @@ fn sqlite_row_to_mint_quote(row: Vec<Column>) -> Result<MintQuote, Error> {
request,
state,
expiry,
secret_key
secret_key,
row_method,
row_amount_minted,
row_amount_paid
) = row
);
let amount: u64 = column_as_number!(amount);
let amount: Option<i64> = column_as_nullable_number!(amount);
let amount_paid: u64 = column_as_number!(row_amount_paid);
let amount_minted: u64 = column_as_number!(row_amount_minted);
let payment_method =
PaymentMethod::from_str(&column_as_string!(row_method)).map_err(Error::from)?;
Ok(MintQuote {
id: column_as_string!(id),
mint_url: column_as_string!(mint_url, MintUrl::from_str),
amount: Amount::from(amount),
amount: amount.and_then(Amount::from_i64),
unit: column_as_string!(unit, CurrencyUnit::from_str),
request: column_as_string!(request),
state: column_as_string!(state, MintQuoteState::from_str),
@@ -967,6 +984,9 @@ fn sqlite_row_to_mint_quote(row: Vec<Column>) -> Result<MintQuote, Error> {
secret_key: column_as_nullable_string!(secret_key)
.map(|v| SecretKey::from_str(&v))
.transpose()?,
payment_method,
amount_issued: amount_minted.into(),
amount_paid: amount_paid.into(),
})
}