mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-24 03:54:21 +01:00
[Wallet/mint] P2PK with timelocks (#270)
* p2pk with nostr privatekey and timelocks * add p2pk * fix test * fix test with custom secret * sign whole split transaction * p2pk signature now commits to entire secret and thus to a nonce * use schnorr signatures * revamp P2SH and P2PK with new Secret model * test p2pk * add comments * add nostr private key to tests * fix nostr receive * make format * test redemption after timelock * refactor Server.serialize() * sign sha256(secret) * add optional refund pubkey that triggers after timelock * use nostr private key for now (including nsec parser) * use nostr private key and fix tests * bump version to 0.12.2
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Optional
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
|
||||
from ..core.base import TokenV1, TokenV2, TokenV3, TokenV3Token
|
||||
from ..core.base import Secret, SecretKind, TokenV1, TokenV2, TokenV3, TokenV3Token
|
||||
from ..core.helpers import sum_proofs
|
||||
from ..core.migrations import migrate_databases
|
||||
from ..core.settings import settings
|
||||
@@ -21,12 +23,7 @@ async def init_wallet(wallet: Wallet, load_proofs: bool = True):
|
||||
await wallet.load_proofs(reload=True)
|
||||
|
||||
|
||||
async def redeem_TokenV3_multimint(
|
||||
wallet: Wallet,
|
||||
token: TokenV3,
|
||||
script,
|
||||
signature,
|
||||
):
|
||||
async def redeem_TokenV3_multimint(wallet: Wallet, token: TokenV3):
|
||||
"""
|
||||
Helper function to iterate thruogh a token with multiple mints and redeem them from
|
||||
these mints one keyset at a time.
|
||||
@@ -43,9 +40,7 @@ async def redeem_TokenV3_multimint(
|
||||
await mint_wallet.load_mint()
|
||||
# redeem proofs of this keyset
|
||||
redeem_proofs = [p for p in t.proofs if p.id == keyset]
|
||||
_, _ = await mint_wallet.redeem(
|
||||
redeem_proofs, scnd_script=script, scnd_siganture=signature
|
||||
)
|
||||
_, _ = await mint_wallet.redeem(redeem_proofs)
|
||||
print(f"Received {sum_proofs(redeem_proofs)} sats")
|
||||
|
||||
|
||||
@@ -113,20 +108,9 @@ def deserialize_token_from_string(token: str) -> TokenV3:
|
||||
async def receive(
|
||||
wallet: Wallet,
|
||||
tokenObj: TokenV3,
|
||||
lock: str,
|
||||
):
|
||||
# check for P2SH locks
|
||||
if lock:
|
||||
# load the script and signature of this address from the database
|
||||
assert len(lock.split("P2SH:")) == 2, Exception(
|
||||
"lock has wrong format. Expected P2SH:<address>."
|
||||
)
|
||||
address_split = lock.split("P2SH:")[1]
|
||||
p2shscripts = await get_unused_locks(address_split, db=wallet.db)
|
||||
assert len(p2shscripts) == 1, Exception("lock not found.")
|
||||
script, signature = p2shscripts[0].script, p2shscripts[0].signature
|
||||
else:
|
||||
script, signature = None, None
|
||||
logger.debug(f"receive: {tokenObj}")
|
||||
proofs = [p for t in tokenObj.token for p in t.proofs]
|
||||
|
||||
includes_mint_info: bool = any([t.mint for t in tokenObj.token])
|
||||
|
||||
@@ -135,13 +119,10 @@ async def receive(
|
||||
await redeem_TokenV3_multimint(
|
||||
wallet,
|
||||
tokenObj,
|
||||
script,
|
||||
signature,
|
||||
)
|
||||
else:
|
||||
# this is very legacy code, virtually any token should have mint information
|
||||
# no mint information present, we extract the proofs and use wallet's default mint
|
||||
|
||||
proofs = [p for t in tokenObj.token for p in t.proofs]
|
||||
# first we load the mint URL from the DB
|
||||
keyset_in_token = proofs[0].id
|
||||
assert keyset_in_token
|
||||
@@ -155,7 +136,7 @@ async def receive(
|
||||
os.path.join(settings.cashu_dir, wallet.name),
|
||||
)
|
||||
await mint_wallet.load_mint(keyset_in_token)
|
||||
_, _ = await mint_wallet.redeem(proofs, script, signature)
|
||||
_, _ = await mint_wallet.redeem(proofs)
|
||||
print(f"Received {sum_proofs(proofs)} sats")
|
||||
|
||||
# reload main wallet so the balance updates
|
||||
@@ -170,19 +151,34 @@ async def send(
|
||||
"""
|
||||
Prints token to send to stdout.
|
||||
"""
|
||||
secret_lock = None
|
||||
if lock:
|
||||
assert len(lock) > 21, Exception(
|
||||
"Error: lock has to be at least 22 characters long."
|
||||
)
|
||||
p2sh = False
|
||||
if lock and len(lock.split("P2SH:")) == 2:
|
||||
p2sh = True
|
||||
if not lock.startswith("P2SH:") and not lock.startswith("P2PK:"):
|
||||
raise Exception("Error: lock has to start with P2SH: or P2PK:")
|
||||
# we add a time lock to the P2PK lock by appending the current unix time + 14 days
|
||||
# we use datetime because it's easier to read
|
||||
if lock.startswith("P2PK:") or lock.startswith("P2SH:"):
|
||||
logger.debug(f"Locking token to: {lock}")
|
||||
logger.debug(
|
||||
f"Adding a time lock of {settings.timelock_delta_seconds} seconds."
|
||||
)
|
||||
if lock.startswith("P2SH:"):
|
||||
secret_lock = await wallet.create_p2sh_lock(
|
||||
lock.split(":")[1], timelock=settings.timelock_delta_seconds
|
||||
)
|
||||
elif lock.startswith("P2PK:"):
|
||||
secret_lock = await wallet.create_p2pk_lock(
|
||||
lock.split(":")[1], timelock=settings.timelock_delta_seconds
|
||||
)
|
||||
|
||||
await wallet.load_proofs()
|
||||
if split:
|
||||
await wallet.load_mint()
|
||||
_, send_proofs = await wallet.split_to_send(
|
||||
wallet.proofs, amount, lock, set_reserved=True
|
||||
wallet.proofs, amount, secret_lock, set_reserved=True
|
||||
)
|
||||
else:
|
||||
# get a proof with specific amount
|
||||
|
||||
Reference in New Issue
Block a user