Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions cashu/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,27 +457,22 @@ def from_row(cls, row: Row):

@classmethod
def from_resp_wallet(cls, mint_quote_resp, mint: str, amount: int, unit: str):
# BEGIN: BACKWARDS COMPATIBILITY < 0.16.0: "paid" field to "state"
if mint_quote_resp.state is None:
if mint_quote_resp.paid is True:
mint_quote_resp.state = MintQuoteState.paid
elif mint_quote_resp.paid is False:
mint_quote_resp.state = MintQuoteState.unpaid
# END: BACKWARDS COMPATIBILITY < 0.16.0
# Ensure default fallbacks for backwards compatibility
resp_state = getattr(mint_quote_resp, "state", None) or "unpaid"
return cls(
quote=mint_quote_resp.quote,
method="bolt11",
request=mint_quote_resp.request,
checking_id="",
unit=mint_quote_resp.unit
unit=mint_quote_resp.unit
or unit, # BACKWARDS COMPATIBILITY mint response < 0.17.0
amount=mint_quote_resp.amount
or amount, # BACKWARDS COMPATIBILITY mint response < 0.17.0
state=MintQuoteState(mint_quote_resp.state),
state=MintQuoteState(resp_state),
mint=mint,
expiry=mint_quote_resp.expiry,
expiry=getattr(mint_quote_resp, "expiry", None),
created_time=int(time.time()),
pubkey=mint_quote_resp.pubkey,
pubkey=getattr(mint_quote_resp, "pubkey", None),
)

@property
Expand Down
1 change: 0 additions & 1 deletion cashu/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ class PostMintQuoteResponse(BaseModel):
state: Optional[str] # state of the quote (optional for backwards compat)
expiry: Optional[int] # expiry of the quote
pubkey: Optional[str] = None # NUT-20 quote lock pubkey
paid: Optional[bool] = None # DEPRECATED as per NUT-04 PR #141

@classmethod
def from_mint_quote(cls, mint_quote: MintQuote) -> "PostMintQuoteResponse":
Expand Down
10 changes: 5 additions & 5 deletions cashu/mint/auth/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,8 @@ async def store_mint_quote(
await (conn or db).execute(
f"""
INSERT INTO {db.table_with_schema('mint_quotes')}
(quote, method, request, checking_id, unit, amount, issued, paid, state, created_time, paid_time)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :issued, :paid, :state, :created_time, :paid_time)
(quote, method, request, checking_id, unit, amount, issued, state, created_time, paid_time, pubkey)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :issued, :state, :created_time, :paid_time, :pubkey)
""",
{
"quote": quote.quote,
Expand All @@ -399,14 +399,14 @@ async def store_mint_quote(
"unit": quote.unit,
"amount": quote.amount,
"issued": quote.issued,
"paid": quote.paid,
"state": quote.state.name,
"created_time": db.to_timestamp(
db.timestamp_from_seconds(quote.created_time) or ""
),
"paid_time": db.to_timestamp(
db.timestamp_from_seconds(quote.paid_time) or ""
),
"pubkey": quote.pubkey or "",
},
)

Expand Down Expand Up @@ -468,14 +468,14 @@ async def update_mint_quote(
conn: Optional[Connection] = None,
) -> None:
await (conn or db).execute(
f"UPDATE {db.table_with_schema('mint_quotes')} SET issued = :issued, paid = :paid, state = :state, paid_time = :paid_time WHERE quote = :quote",
f"UPDATE {db.table_with_schema('mint_quotes')} SET issued = :issued, state = :state, paid_time = :paid_time, pubkey = :pubkey WHERE quote = :quote",
{
"issued": quote.issued,
"paid": quote.paid,
"state": quote.state.name,
"paid_time": db.to_timestamp(
db.timestamp_from_seconds(quote.paid_time) or ""
),
"pubkey": quote.pubkey or "",
"quote": quote.quote,
},
)
Expand Down
5 changes: 2 additions & 3 deletions cashu/mint/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,8 @@ async def store_mint_quote(
await (conn or db).execute(
f"""
INSERT INTO {db.table_with_schema('mint_quotes')}
(quote, method, request, checking_id, unit, amount, paid, issued, state, created_time, paid_time, pubkey)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :paid, :issued, :state, :created_time, :paid_time, :pubkey)
(quote, method, request, checking_id, unit, amount, issued, state, created_time, paid_time, pubkey)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :issued, :state, :created_time, :paid_time, :pubkey)
""",
{
"quote": quote.quote,
Expand All @@ -615,7 +615,6 @@ async def store_mint_quote(
"checking_id": quote.checking_id,
"unit": quote.unit,
"amount": quote.amount,
"paid": quote.paid, # this is deprecated! we need to store it because we have a NOT NULL constraint | we could also remove the column but sqlite doesn't support that (we would have to make a new table)
"issued": quote.issued, # this is deprecated! we need to store it because we have a NOT NULL constraint | we could also remove the column but sqlite doesn't support that (we would have to make a new table)
"state": quote.state.value,
"created_time": db.to_timestamp(
Expand Down
2 changes: 1 addition & 1 deletion cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ async def mint(
raise TransactionError("Mint quote already pending.")
if quote.issued:
raise TransactionError("Mint quote already issued.")
if not quote.paid:
if quote.state != MintQuoteState.paid:
raise QuoteNotPaidError()

previous_state = quote.state
Expand Down
43 changes: 42 additions & 1 deletion cashu/mint/migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,8 @@ async def m018_duplicate_deprecated_keyset_ids(db: Database):
if keyset.version_tuple < (0, 15):
keyset_copy.id = derive_keyset_id(keyset_copy.public_keys)
else:
keyset_copy.id = derive_keyset_id_deprecated(keyset_copy.public_keys)
keyset_copy.id = derive_keyset_id_deprecated(
keyset_copy.public_keys)
duplicated_keysets.append(keyset_copy)

for keyset in duplicated_keysets:
Expand Down Expand Up @@ -1155,3 +1156,43 @@ async def m029_remove_overlong_witness_values(db: Database):
f"UPDATE {db.table_with_schema('proofs_pending')} SET witness = NULL "
"WHERE witness IS NOT NULL AND LENGTH(witness) > 1024"
)

async def m030_remove_paid_from_mint_quote(db: Database):
"""
Remove the deprecated 'paid' field from mint_quotes
The 'state' column now fully represents payment status.
"""
async with db.connect() as conn:
if conn.type == "SQLITE":
await conn.execute("PRAGMA foreign_keys=OFF;")

# Recreate mint_quotes without 'paid'
await conn.execute("""
CREATE TABLE mint_quotes_new (
quote TEXT PRIMARY KEY,
method TEXT,
request TEXT,
checking_id TEXT,
unit TEXT,
amount INT,
issued NUM,
created_time NUM,
paid_time NUM,
state TEXT,
pubkey TEXT
);
""")

# Copy data
await conn.execute("""
INSERT INTO mint_quotes_new
SELECT quote, method, request, checking_id, unit, amount,
issued, created_time, paid_time, state, pubkey
FROM mint_quotes;
""")

# Swap tables
await conn.execute("DROP TABLE mint_quotes;")
await conn.execute("ALTER TABLE mint_quotes_new RENAME TO mint_quotes;")

await conn.execute("PRAGMA foreign_keys=ON;")
2 changes: 0 additions & 2 deletions cashu/mint/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ async def mint_quote(
request=quote.request,
amount=quote.amount,
unit=quote.unit,
paid=quote.paid, # deprecated
state=quote.state.value,
expiry=quote.expiry,
pubkey=quote.pubkey,
Expand All @@ -195,7 +194,6 @@ async def get_mint_quote(request: Request, quote: str) -> PostMintQuoteResponse:
request=mint_quote.request,
amount=mint_quote.amount,
unit=mint_quote.unit,
paid=mint_quote.paid, # deprecated
state=mint_quote.state.value,
expiry=mint_quote.expiry,
pubkey=mint_quote.pubkey,
Expand Down
11 changes: 0 additions & 11 deletions tests/mint/test_mint_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,6 @@ async def test_mint_quote(ledger: Ledger):
assert resp_quote.unit == "sat"
assert resp_quote.request == result["request"]

# check if DEPRECATED paid flag is also returned
assert result["paid"] is False
assert resp_quote.paid is False

invoice = bolt11.decode(result["request"])
assert invoice.amount_msat == 100 * 1000

Expand Down Expand Up @@ -239,9 +235,6 @@ async def test_mint_quote(ledger: Ledger):
assert resp_quote.unit == "sat"
assert resp_quote.request == result["request"]

# check if DEPRECATED paid flag is also returned
assert result2["paid"] is True
assert resp_quote.paid is True
assert resp_quote.pubkey == "02" + "00" * 32


Expand Down Expand Up @@ -350,10 +343,6 @@ async def test_melt_quote_internal(ledger: Ledger, wallet: Wallet):
assert resp_quote.unit == "sat"
assert resp_quote.request == request

# check if DEPRECATED paid flag is also returned
assert result["paid"] is False
assert resp_quote.paid is False

invoice_obj = bolt11.decode(request)

expiry = None
Expand Down
Loading