Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 0 additions & 7 deletions cashu/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,13 +343,6 @@ def from_row(cls, row: Row, change: Optional[List[BlindedSignature]] = None):

@classmethod
def from_resp_wallet(cls, melt_quote_resp, mint: str, unit: str, request: str):
# BEGIN: BACKWARDS COMPATIBILITY < 0.16.0: "paid" field to "state"
if melt_quote_resp.state is None:
if melt_quote_resp.paid is True:
melt_quote_resp.state = MeltQuoteState.paid
elif melt_quote_resp.paid is False:
melt_quote_resp.state = MeltQuoteState.unpaid
# END: BACKWARDS COMPATIBILITY < 0.16.0
return cls(
quote=melt_quote_resp.quote,
method="bolt11",
Comment thread
KvngMikey marked this conversation as resolved.
Expand Down
5 changes: 0 additions & 5 deletions cashu/core/models/melt_quote.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ class PostMeltQuoteResponse(BaseModel):
str
] # output payment request (optional for BACKWARDS COMPAT mint response < 0.17.0)
fee_reserve: int # input fee reserve
paid: Optional[bool] = (
None # whether the request has been paid # DEPRECATED as per NUT PR #136
)
state: Optional[str] # state of the quote
expiry: Optional[int] # expiry of the quote
payment_preimage: Optional[str] = None # payment preimage
Expand All @@ -60,6 +57,4 @@ def from_melt_quote(cls, melt_quote: MeltQuote) -> "PostMeltQuoteResponse":
to_dict = melt_quote.model_dump()
# turn state into string
to_dict["state"] = melt_quote.state.value
# add deprecated "paid" field
to_dict["paid"] = melt_quote.paid
return cls.model_validate(to_dict)
12 changes: 5 additions & 7 deletions cashu/mint/auth/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ async def store_melt_quote(
await (conn or db).execute(
f"""
INSERT INTO {db.table_with_schema('melt_quotes')}
(quote, method, request, checking_id, unit, amount, fee_reserve, paid, state, created_time, paid_time, fee_paid, proof, change, expiry)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :fee_reserve, :paid, :state, :created_time, :paid_time, :fee_paid, :proof, :change, :expiry)
(quote, method, request, checking_id, unit, amount, fee_reserve, state, created_time, paid_time, fee_paid, proof, change, expiry)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :fee_reserve, :state, :created_time, :paid_time, :fee_paid, :proof, :change, :expiry)
""",
{
"quote": quote.quote,
Expand All @@ -511,8 +511,7 @@ async def store_melt_quote(
"unit": quote.unit,
"amount": quote.amount,
"fee_reserve": quote.fee_reserve or 0,
"paid": quote.paid,
"state": quote.state.name,
"state": quote.state.value,
"created_time": db.to_timestamp(
db.timestamp_from_seconds(quote.created_time) or ""
),
Expand Down Expand Up @@ -571,11 +570,10 @@ async def update_melt_quote(
) -> None:
await (conn or db).execute(
f"""
UPDATE {db.table_with_schema('melt_quotes')} SET paid = :paid, state = :state, fee_paid = :fee_paid, paid_time = :paid_time, proof = :proof, change = :change WHERE quote = :quote
UPDATE {db.table_with_schema('melt_quotes')} SET state = :state, fee_paid = :fee_paid, paid_time = :paid_time, proof = :proof, change = :change WHERE quote = :quote
""",
{
"paid": quote.paid,
"state": quote.state.name,
"state": quote.state.value,
"fee_paid": quote.fee_paid,
"paid_time": db.to_timestamp(
db.timestamp_from_seconds(quote.paid_time) or ""
Expand Down
5 changes: 2 additions & 3 deletions cashu/mint/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,8 +758,8 @@ async def store_melt_quote(
await (conn or db).execute(
f"""
INSERT INTO {db.table_with_schema("melt_quotes")}
(quote, method, request, checking_id, unit, amount, fee_reserve, state, paid, created_time, paid_time, fee_paid, proof, expiry)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :fee_reserve, :state, :paid, :created_time, :paid_time, :fee_paid, :proof, :expiry)
(quote, method, request, checking_id, unit, amount, fee_reserve, state, created_time, paid_time, fee_paid, proof, expiry)
VALUES (:quote, :method, :request, :checking_id, :unit, :amount, :fee_reserve, :state, :created_time, :paid_time, :fee_paid, :proof, :expiry)
""",
{
"quote": quote.quote,
Expand All @@ -770,7 +770,6 @@ async def store_melt_quote(
"amount": quote.amount,
"fee_reserve": quote.fee_reserve or 0,
"state": quote.state.value,
"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)
"created_time": db.to_timestamp(
db.timestamp_from_seconds(quote.created_time) or ""
),
Expand Down
5 changes: 2 additions & 3 deletions cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,6 @@ async def melt_quote(
unit=quote.unit,
request=quote.request,
fee_reserve=quote.fee_reserve,
paid=quote.paid, # deprecated
state=quote.state.value,
expiry=quote.expiry,
)
Expand Down Expand Up @@ -946,7 +945,7 @@ async def melt_mint_settle_internally(
return melt_quote

# we settle the transaction internally
if melt_quote.paid:
if melt_quote.state == MeltQuoteState.paid:
raise TransactionError("melt quote already paid")

# verify amounts from bolt11 invoice
Expand Down Expand Up @@ -1102,7 +1101,7 @@ async def melt(
# if the melt corresponds to an internal mint, mark both as paid
melt_quote = await self.melt_mint_settle_internally(melt_quote, proofs)
# quote not paid yet (not internal), pay it with the backend
if not melt_quote.paid:
if melt_quote.state != MeltQuoteState.paid:
logger.debug(f"Lightning: pay invoice {melt_quote.request}")
Comment thread
KvngMikey marked this conversation as resolved.
Outdated
try:
payment = await self.backends[method][unit].pay_invoice(
Expand Down
45 changes: 45 additions & 0 deletions cashu/mint/migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1261,3 +1261,48 @@ async def m035_add_last_checked_to_mint_quotes(db: Database):
ADD COLUMN last_checked TIMESTAMP NULL
"""
)


async def m036_remove_paid_from_melt_quote(db: Database):
"""Remove the deprecated 'paid' field from melt_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;")
await conn.execute(
f"""
CREATE TABLE {db.table_with_schema('melt_quotes_new')} (
quote TEXT NOT NULL,
method TEXT NOT NULL,
request TEXT NOT NULL,
checking_id TEXT NOT NULL,
unit TEXT NOT NULL,
amount {db.big_int} NOT NULL,
fee_reserve {db.big_int},
created_time TIMESTAMP,
paid_time TIMESTAMP,
fee_paid {db.big_int},
proof TEXT,
state TEXT,
expiry TIMESTAMP,
UNIQUE (quote)
);
"""
)
await conn.execute(
f"""
INSERT INTO {db.table_with_schema('melt_quotes_new')}
(quote, method, request, checking_id, unit, amount, fee_reserve, created_time, paid_time, fee_paid, proof, state, expiry)
SELECT quote, method, request, checking_id, unit, amount, fee_reserve, created_time, paid_time, fee_paid, proof, state, expiry
FROM {db.table_with_schema('melt_quotes')};
"""
)
await conn.execute(f"DROP TABLE {db.table_with_schema('melt_quotes')};")
await conn.execute(
f"ALTER TABLE {db.table_with_schema('melt_quotes_new')} RENAME TO {db.table_with_schema('melt_quotes')};"
)
await conn.execute("PRAGMA foreign_keys=ON;")
Comment thread
KvngMikey marked this conversation as resolved.
elif conn.type == "POSTGRES":
await conn.execute(
f"ALTER TABLE {db.table_with_schema('melt_quotes')} DROP COLUMN IF EXISTS paid;"
)
1 change: 0 additions & 1 deletion cashu/mint/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ async def get_melt_quote(request: Request, quote: str) -> PostMeltQuoteResponse:
unit=melt_quote.unit,
request=melt_quote.request,
fee_reserve=melt_quote.fee_reserve,
paid=melt_quote.paid,
state=melt_quote.state.value,
expiry=melt_quote.expiry,
payment_preimage=melt_quote.payment_preimage,
Expand Down
1 change: 0 additions & 1 deletion cashu/wallet/v1_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,6 @@ def _meltrequest_include_fields(
unit="sat",
request="lnbc0",
fee_reserve=0,
paid=ret.paid or False,
state=(
MeltQuoteState.paid.value
if ret.paid
Expand Down
18 changes: 9 additions & 9 deletions tests/fuzz/test_fuzz_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,17 +171,17 @@ def test_fuzz_melt_quote(quote, method, request, checking_id, unit, amount, fee_

# Test property accessors
if state == MeltQuoteState.paid:
assert mq.paid
assert not mq.unpaid
assert not mq.pending
assert mq.state == MeltQuoteState.paid
assert mq.state != MeltQuoteState.unpaid
assert mq.state != MeltQuoteState.pending
elif state == MeltQuoteState.unpaid:
assert not mq.paid
assert mq.unpaid
assert not mq.pending
assert mq.state != MeltQuoteState.paid
assert mq.state == MeltQuoteState.unpaid
assert mq.state != MeltQuoteState.pending
elif state == MeltQuoteState.pending:
assert not mq.paid
assert not mq.unpaid
assert mq.pending
assert mq.state != MeltQuoteState.paid
assert mq.state != MeltQuoteState.unpaid
assert mq.state == MeltQuoteState.pending

@given(
quote=st.text(min_size=1, max_size=50),
Expand Down
20 changes: 0 additions & 20 deletions tests/mint/test_mint_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,26 +362,6 @@ async def test_melt_quote_internal(ledger: Ledger, wallet: Wallet):

assert result["expiry"] == expiry

# # get melt quote again from api
# response = httpx.get(
# f"{BASE_URL}/v1/melt/quote/bolt11/{result['quote']}",
# )
# assert response.status_code == 200, f"{response.url} {response.status_code}"
# result2 = response.json()
# assert result2["quote"] == result["quote"]

# # deserialize the response
# resp_quote = PostMeltQuoteResponse(**result2)
# assert resp_quote.quote == result["quote"]
# assert resp_quote.payment_preimage is not None
# assert len(resp_quote.payment_preimage) == 64
# assert resp_quote.change is not None
# assert resp_quote.state == MeltQuoteState.paid.value

# # check if DEPRECATED paid flag is also returned
# assert result2["paid"] is True
# assert resp_quote.paid is True


@pytest.mark.asyncio
@pytest.mark.skipif(
Expand Down
Loading