show used locks

This commit is contained in:
callebtc
2022-10-03 01:31:48 +02:00
parent cd89321561
commit 1b43966544
4 changed files with 106 additions and 15 deletions

View File

@@ -7,6 +7,16 @@ from pydantic import BaseModel
class P2SHScript(BaseModel): class P2SHScript(BaseModel):
script: str script: str
signature: str signature: str
address: str = None
@classmethod
def from_row(cls, row: Row):
return cls(
address=row[0],
script=row[1],
signature=row[2],
used=row[3],
)
class Proof(BaseModel): class Proof(BaseModel):

View File

@@ -12,7 +12,6 @@ from itertools import groupby
from operator import itemgetter from operator import itemgetter
import click import click
from bech32 import bech32_decode, bech32_encode, convertbits
from loguru import logger from loguru import logger
import cashu.core.bolt11 as bolt11 import cashu.core.bolt11 as bolt11
@@ -20,10 +19,9 @@ from cashu.core.base import Proof
from cashu.core.bolt11 import Invoice from cashu.core.bolt11 import Invoice
from cashu.core.helpers import fee_reserve from cashu.core.helpers import fee_reserve
from cashu.core.migrations import migrate_databases from cashu.core.migrations import migrate_databases
from cashu.core.script import *
from cashu.core.settings import CASHU_DIR, DEBUG, LIGHTNING, MINT_URL, VERSION, ENV_FILE from cashu.core.settings import CASHU_DIR, DEBUG, LIGHTNING, MINT_URL, VERSION, ENV_FILE
from cashu.wallet import migrations from cashu.wallet import migrations
from cashu.wallet.crud import get_reserved_proofs from cashu.wallet.crud import get_reserved_proofs, get_unused_locks
from cashu.wallet.wallet import Wallet as Wallet from cashu.wallet.wallet import Wallet as Wallet
@@ -235,10 +233,11 @@ async def pay(ctx, invoice: str):
@click.pass_context @click.pass_context
@coro @coro
async def lock(ctx): async def lock(ctx):
alice_privkey = step0_carol_privkey() wallet: Wallet = ctx.obj["WALLET"]
txin_redeemScript = step0_carol_checksig_redeemscrip(alice_privkey.pub) p2shscript = await wallet.create_p2sh_lock()
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript) txin_p2sh_address = p2shscript.address
# print("Redeem script:", txin_redeemScript.__repr__()) txin_redeemScript_b64 = p2shscript.script
txin_signature_b64 = p2shscript.signature
print("---- Pay to script hash (P2SH) ----\n") print("---- Pay to script hash (P2SH) ----\n")
print("Use a lock to receive coins that only you can unlock.") print("Use a lock to receive coins that only you can unlock.")
print("") print("")
@@ -248,10 +247,6 @@ async def lock(ctx):
f"Send coins to this lock:\n\ncashu send <amount> --lock P2SH:{txin_p2sh_address}" f"Send coins to this lock:\n\ncashu send <amount> --lock P2SH:{txin_p2sh_address}"
) )
print("") print("")
txin_signature = step2_carol_sign_tx(txin_redeemScript, alice_privkey).scriptSig
txin_redeemScript_b64 = base64.urlsafe_b64encode(txin_redeemScript).decode()
txin_signature_b64 = base64.urlsafe_b64encode(txin_signature).decode()
print( print(
"!!! The command below is private. Do not share. You have to remember it. Do not lose. !!!\n" "!!! The command below is private. Do not share. You have to remember it. Do not lose. !!!\n"
) )
@@ -260,6 +255,26 @@ async def lock(ctx):
) )
@cli.command("locks", help="Show all receiving locks.")
@click.pass_context
@coro
async def locks(ctx):
wallet: Wallet = ctx.obj["WALLET"]
locks = await get_unused_locks(db=wallet.db)
if len(locks):
print("")
print(f"--------------------------\n")
for l in locks:
print(f"Address: {l.address}")
print(f"Script: {l.script}")
print(f"Signature: {l.signature}")
print("")
print(f"Receive: cashu receive <coin> --unlock {l.script}:{l.signature}")
print("")
print(f"--------------------------\n")
return True
@cli.command("info", help="Information about Cashu wallet.") @cli.command("info", help="Information about Cashu wallet.")
@click.pass_context @click.pass_context
@coro @coro

View File

@@ -1,7 +1,7 @@
import time import time
from typing import Optional from typing import Optional
from cashu.core.base import Proof from cashu.core.base import Proof, P2SHScript
from cashu.core.db import Connection, Database from cashu.core.db import Connection, Database
@@ -113,3 +113,50 @@ async def secret_used(
(secret), (secret),
) )
return rows is not None return rows is not None
async def store_p2sh(
p2sh: P2SHScript,
db: Database,
conn: Optional[Connection] = None,
):
await (conn or db).execute(
"""
INSERT INTO p2sh
(address, script, signature, used)
VALUES (?, ?, ?, ?)
""",
(p2sh.address, p2sh.script, p2sh.signature, False),
)
async def get_unused_locks(
db: Database,
conn: Optional[Connection] = None,
):
rows = await (conn or db).fetchall(
"""
SELECT * from p2sh
WHERE used = 0
"""
)
return [P2SHScript.from_row(r) for r in rows]
async def update_p2sh_used(
p2sh: P2SHScript,
used: bool,
db: Database = None,
conn: Optional[Connection] = None,
):
clauses = []
values = []
clauses.append("used = ?")
values.append(used)
await (conn or db).execute(
f"UPDATE proofs SET {', '.join(clauses)} WHERE address = ?",
(*values, str(p2sh.address)),
)

View File

@@ -18,6 +18,12 @@ from cashu.core.base import (
Proof, Proof,
SplitPayload, SplitPayload,
) )
from cashu.core.script import (
step0_carol_privkey,
step0_carol_checksig_redeemscrip,
step1_carol_create_p2sh_address,
step2_carol_sign_tx,
)
from cashu.core.db import Database from cashu.core.db import Database
from cashu.core.secp import PublicKey from cashu.core.secp import PublicKey
from cashu.core.settings import DEBUG from cashu.core.settings import DEBUG
@@ -28,6 +34,7 @@ from cashu.wallet.crud import (
secret_used, secret_used,
store_proof, store_proof,
update_proof_reserved, update_proof_reserved,
store_p2sh,
) )
@@ -194,9 +201,6 @@ class LedgerAPI:
return fst_proofs, snd_proofs return fst_proofs, snd_proofs
async def create_p2sh_lock(self, secrets: List[str]):
return None
async def check_spendable(self, proofs: List[Proof]): async def check_spendable(self, proofs: List[Proof]):
payload = CheckPayload(proofs=proofs) payload = CheckPayload(proofs=proofs)
return_dict = requests.post( return_dict = requests.post(
@@ -334,6 +338,21 @@ class Wallet(LedgerAPI):
filter(lambda p: p["secret"] not in invalidate_secrets, self.proofs) filter(lambda p: p["secret"] not in invalidate_secrets, self.proofs)
) )
async def create_p2sh_lock(self):
alice_privkey = step0_carol_privkey()
txin_redeemScript = step0_carol_checksig_redeemscrip(alice_privkey.pub)
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
txin_signature = step2_carol_sign_tx(txin_redeemScript, alice_privkey).scriptSig
txin_redeemScript_b64 = base64.urlsafe_b64encode(txin_redeemScript).decode()
txin_signature_b64 = base64.urlsafe_b64encode(txin_signature).decode()
p2shScript = P2SHScript(
script=txin_redeemScript_b64,
signature=txin_signature_b64,
address=str(txin_p2sh_address),
)
await store_p2sh(p2shScript, db=self.db)
return p2shScript
@property @property
def balance(self): def balance(self):
return sum(p["amount"] for p in self.proofs) return sum(p["amount"] for p in self.proofs)