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