mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 02:54:20 +01:00
burn all spent tokens with cashu burn -a
This commit is contained in:
@@ -144,7 +144,7 @@ async def melt(payload: MeltPayload):
|
||||
|
||||
@app.post("/check")
|
||||
async def check_spendable(payload: CheckPayload):
|
||||
return {"spendable": await ledger.check_spendable(payload.proofs)}
|
||||
return await ledger.check_spendable(payload.proofs)
|
||||
|
||||
|
||||
@app.post("/split")
|
||||
|
||||
@@ -13,9 +13,14 @@ from core.secp import PrivateKey, PublicKey
|
||||
from core.settings import LIGHTNING, MAX_ORDER
|
||||
from core.split import amount_split
|
||||
from lightning import WALLET
|
||||
from mint.crud import (get_lightning_invoice, get_proofs_used,
|
||||
invalidate_proof, store_lightning_invoice,
|
||||
store_promise, update_lightning_invoice)
|
||||
from mint.crud import (
|
||||
get_lightning_invoice,
|
||||
get_proofs_used,
|
||||
invalidate_proof,
|
||||
store_lightning_invoice,
|
||||
store_promise,
|
||||
update_lightning_invoice,
|
||||
)
|
||||
|
||||
|
||||
class Ledger:
|
||||
@@ -219,9 +224,7 @@ class Ledger:
|
||||
|
||||
async def check_spendable(self, proofs: List[Proof]):
|
||||
"""Checks if all provided proofs are valid and still spendable (i.e. have not been spent)."""
|
||||
if not all([self._check_spendable(p) for p in proofs]):
|
||||
return False
|
||||
return True
|
||||
return {i: self._check_spendable(p) for i, p in enumerate(proofs)}
|
||||
|
||||
async def split(
|
||||
self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage]
|
||||
|
||||
@@ -16,6 +16,7 @@ from core.helpers import fee_reserve
|
||||
from core.migrations import migrate_databases
|
||||
from core.settings import LIGHTNING, MINT_URL
|
||||
from wallet import migrations
|
||||
from wallet.crud import get_reserved_proofs
|
||||
from wallet.wallet import Wallet as Wallet
|
||||
|
||||
|
||||
@@ -121,14 +122,23 @@ async def receive(ctx, token: str):
|
||||
|
||||
|
||||
@cli.command("burn", help="Burn spent tokens.")
|
||||
@click.argument("token", type=str)
|
||||
@click.argument("token", required=False, type=str)
|
||||
@click.option("--all", "-a", default=False, is_flag=True, help="Burn all spent tokens.")
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def burn(ctx, token: str):
|
||||
async def burn(ctx, token: str, all: bool):
|
||||
wallet: Wallet = ctx.obj["WALLET"]
|
||||
await init_wallet(wallet)
|
||||
if not (all or token) or (token and all):
|
||||
print("Error: enter a token or use --all to burn all pending tokens.")
|
||||
return
|
||||
if all:
|
||||
proofs = await get_reserved_proofs(wallet.db)
|
||||
else:
|
||||
proofs = [
|
||||
Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(token))
|
||||
]
|
||||
wallet.status()
|
||||
proofs = [Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(token))]
|
||||
await wallet.invalidate(proofs)
|
||||
wallet.status()
|
||||
|
||||
|
||||
@@ -38,6 +38,20 @@ async def get_proofs(
|
||||
return [Proof.from_row(r) for r in rows]
|
||||
|
||||
|
||||
async def get_reserved_proofs(
|
||||
db: Database,
|
||||
conn: Optional[Connection] = None,
|
||||
):
|
||||
|
||||
rows = await (conn or db).fetchall(
|
||||
"""
|
||||
SELECT * from proofs
|
||||
WHERE reserved
|
||||
"""
|
||||
)
|
||||
return [Proof.from_row(r) for r in rows]
|
||||
|
||||
|
||||
async def invalidate_proof(
|
||||
proof: Proof,
|
||||
db: Database,
|
||||
|
||||
@@ -4,13 +4,19 @@ from typing import List
|
||||
import requests
|
||||
|
||||
import core.b_dhke as b_dhke
|
||||
from core.base import (BlindedMessage, BlindedSignature, CheckPayload,
|
||||
MeltPayload, MintPayloads, Proof, SplitPayload)
|
||||
from core.base import (
|
||||
BlindedMessage,
|
||||
BlindedSignature,
|
||||
CheckPayload,
|
||||
MeltPayload,
|
||||
MintPayloads,
|
||||
Proof,
|
||||
SplitPayload,
|
||||
)
|
||||
from core.db import Database
|
||||
from core.secp import PublicKey
|
||||
from core.split import amount_split
|
||||
from wallet.crud import (get_proofs, invalidate_proof, store_proof,
|
||||
update_proof_reserved)
|
||||
from wallet.crud import get_proofs, invalidate_proof, store_proof, update_proof_reserved
|
||||
|
||||
|
||||
class LedgerAPI:
|
||||
@@ -113,9 +119,8 @@ class LedgerAPI:
|
||||
self.url + "/check",
|
||||
json=payload.dict(),
|
||||
).json()
|
||||
if "spendable" in return_dict and return_dict["spendable"]:
|
||||
return True
|
||||
return False
|
||||
|
||||
return return_dict
|
||||
|
||||
async def pay_lightning(self, proofs: List[Proof], amount: int, invoice: str):
|
||||
payload = MeltPayload(proofs=proofs, amount=amount, invoice=invoice)
|
||||
@@ -197,14 +202,14 @@ class Wallet(LedgerAPI):
|
||||
return await super().check_spendable(proofs)
|
||||
|
||||
async def invalidate(self, proofs):
|
||||
# first we make sure that the server has invalidated these proofs
|
||||
if await self.check_spendable(proofs):
|
||||
raise Exception("tokens not yet spent.")
|
||||
|
||||
# TODO: check with server if they were redeemed already
|
||||
for proof in proofs:
|
||||
await invalidate_proof(proof, db=self.db)
|
||||
invalidate_secrets = [p["secret"] for p in proofs]
|
||||
"""Invalidates all spendable tokens supplied in proofs."""
|
||||
spendables = await self.check_spendable(proofs)
|
||||
invalidated_proofs = []
|
||||
for idx, spendable in spendables.items():
|
||||
if not spendable:
|
||||
invalidated_proofs.append(proofs[int(idx)])
|
||||
await invalidate_proof(proofs[int(idx)], db=self.db)
|
||||
invalidate_secrets = [p["secret"] for p in invalidated_proofs]
|
||||
self.proofs = list(
|
||||
filter(lambda p: p["secret"] not in invalidate_secrets, self.proofs)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user