mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 18:44:20 +01:00
refactor
This commit is contained in:
@@ -40,6 +40,8 @@ from cashu.wallet.crud import (
|
|||||||
)
|
)
|
||||||
from cashu.wallet.wallet import Wallet as Wallet
|
from cashu.wallet.wallet import Wallet as Wallet
|
||||||
|
|
||||||
|
from .cli_helpers import verify_mints, redeem_multimint
|
||||||
|
|
||||||
|
|
||||||
async def init_wallet(wallet: Wallet):
|
async def init_wallet(wallet: Wallet):
|
||||||
"""Performs migrations and loads proofs from db."""
|
"""Performs migrations and loads proofs from db."""
|
||||||
@@ -193,18 +195,28 @@ async def balance(ctx, verbose):
|
|||||||
print("")
|
print("")
|
||||||
for k, v in keyset_balances.items():
|
for k, v in keyset_balances.items():
|
||||||
print(
|
print(
|
||||||
f"Keyset: {k or 'undefined'} Balance: {v['balance']} sat (available: {v['available']} sat)"
|
f"Keyset: {k or 'undefined'} - Balance: {v['available']} sat (with pending: {v['balance']} sat)"
|
||||||
)
|
)
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
mint_balances = await wallet.balance_per_minturl()
|
mint_balances = await wallet.balance_per_minturl()
|
||||||
if len(mint_balances) > 1:
|
|
||||||
|
# if we have a balance on a non-default mint
|
||||||
|
show_mints = False
|
||||||
|
keysets = [k for k, v in wallet.balance_per_keyset().items()]
|
||||||
|
for k in keysets:
|
||||||
|
ks = await get_keyset(id=str(k), db=wallet.db)
|
||||||
|
if ks and ks.mint_url != ctx.obj["HOST"]:
|
||||||
|
show_mints = True
|
||||||
|
|
||||||
|
# or we have a balance on more than one mint
|
||||||
# show balances per mint
|
# show balances per mint
|
||||||
|
if len(mint_balances) > 1 or show_mints:
|
||||||
print(f"You have balances in {len(mint_balances)} mints:")
|
print(f"You have balances in {len(mint_balances)} mints:")
|
||||||
print("")
|
print("")
|
||||||
for k, v in mint_balances.items():
|
for k, v in mint_balances.items():
|
||||||
print(
|
print(
|
||||||
f"Mint: {k or 'undefined'} Balance: {v['balance']} sat (available: {v['available']} sat)"
|
f"Mint: {k or 'undefined'} - Balance: {v['available']} sat (with pending: {v['balance']} sat)"
|
||||||
)
|
)
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
@@ -271,6 +283,8 @@ async def receive(ctx, token: str, lock: str):
|
|||||||
wallet: Wallet = ctx.obj["WALLET"]
|
wallet: Wallet = ctx.obj["WALLET"]
|
||||||
await wallet.load_mint()
|
await wallet.load_mint()
|
||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
# extract script and signature from P2SH lock
|
||||||
if lock:
|
if lock:
|
||||||
# load the script and signature of this address from the database
|
# load the script and signature of this address from the database
|
||||||
assert len(lock.split("P2SH:")) == 2, Exception(
|
assert len(lock.split("P2SH:")) == 2, Exception(
|
||||||
@@ -285,56 +299,31 @@ async def receive(ctx, token: str, lock: str):
|
|||||||
else:
|
else:
|
||||||
script, signature = None, None
|
script, signature = None, None
|
||||||
|
|
||||||
|
# we support old tokens (< 0.7) without mint information and (W3siaWQ...)
|
||||||
|
# new tokens (>= 0.7) with multiple mint support (eyJ0b2...)
|
||||||
try:
|
try:
|
||||||
# backwards compatibility < 0.7.0: tokens without mint information
|
# backwards compatibility: tokens without mint information
|
||||||
proofs = [Proof(**p) for p in json.loads(base64.urlsafe_b64decode(token))]
|
proofs = [Proof(**p) for p in json.loads(base64.urlsafe_b64decode(token))]
|
||||||
_, _ = await wallet.redeem(proofs, scnd_script=script, scnd_siganture=signature)
|
_, _ = await wallet.redeem(proofs, scnd_script=script, scnd_siganture=signature)
|
||||||
except:
|
except:
|
||||||
|
# assume token with mint information
|
||||||
dtoken = json.loads(base64.urlsafe_b64decode(token))
|
dtoken = json.loads(base64.urlsafe_b64decode(token))
|
||||||
assert "tokens" in dtoken, Exception("no proofs in token")
|
assert "tokens" in dtoken, Exception("no proofs in token")
|
||||||
|
includes_mint_info: bool = "mints" in dtoken and dtoken.get("mints") is not None
|
||||||
|
|
||||||
# if there is a `mints` field in the token
|
# if there is a `mints` field in the token
|
||||||
# we get the mint information in the token and load the keys of each mint
|
# we check whether the token has mints that we don't know yet
|
||||||
# we then redeem the tokens for each keyset individually
|
# and ask the user if they want to trust the new mitns
|
||||||
if "mints" in dtoken and dtoken.get("mints") is not None:
|
if includes_mint_info:
|
||||||
for mint_id in dtoken.get("mints"):
|
# we ask the user to confirm any new mints the tokens may include
|
||||||
for keyset in set(dtoken["mints"][mint_id]["ks"]):
|
await verify_mints(ctx, dtoken)
|
||||||
mint_url = dtoken["mints"][mint_id]["url"]
|
# proceed with redemption
|
||||||
# init a temporary wallet object
|
await redeem_multimint(ctx, dtoken, script, signature)
|
||||||
keyset_wallet = Wallet(
|
# reload main wallet so the balance updates
|
||||||
mint_url, os.path.join(CASHU_DIR, ctx.obj["WALLET_NAME"])
|
|
||||||
)
|
|
||||||
|
|
||||||
# first we check whether we know this mint already and ask the user
|
|
||||||
mint_keysets = await get_keyset(id=keyset, db=keyset_wallet.db)
|
|
||||||
if mint_keysets is None:
|
|
||||||
click.confirm(
|
|
||||||
f"Do you want to receive tokens from mint {mint_url}?",
|
|
||||||
abort=True,
|
|
||||||
default=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# make sure that this mint indeed supports this keyset
|
|
||||||
mint_keysets = await keyset_wallet._get_keysets(mint_url)
|
|
||||||
if keyset in mint_keysets["keysets"]:
|
|
||||||
# load the keys
|
|
||||||
await keyset_wallet.load_mint(keyset_id=keyset)
|
|
||||||
|
|
||||||
# redeem proofs of this keyset
|
|
||||||
redeem_proofs = [
|
|
||||||
Proof(**p)
|
|
||||||
for p in dtoken["tokens"]
|
|
||||||
if Proof(**p).id == keyset
|
|
||||||
]
|
|
||||||
_, _ = await keyset_wallet.redeem(
|
|
||||||
redeem_proofs, scnd_script=script, scnd_siganture=signature
|
|
||||||
)
|
|
||||||
keyset_wallet.db.connect()
|
|
||||||
|
|
||||||
# reload proofs to update the main wallet's balance
|
|
||||||
await wallet.load_proofs()
|
await wallet.load_proofs()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# no mint information present, assume default mint
|
# no mint information present, use wallet's default mint
|
||||||
proofs = [Proof(**p) for p in dtoken["tokens"]]
|
proofs = [Proof(**p) for p in dtoken["tokens"]]
|
||||||
_, _ = await wallet.redeem(
|
_, _ = await wallet.redeem(
|
||||||
proofs, scnd_script=script, scnd_siganture=signature
|
proofs, scnd_script=script, scnd_siganture=signature
|
||||||
|
|||||||
67
cashu/wallet/cli_helpers.py
Normal file
67
cashu/wallet/cli_helpers.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import click
|
||||||
|
import os
|
||||||
|
from cashu.core.settings import CASHU_DIR
|
||||||
|
from cashu.wallet.crud import get_keyset
|
||||||
|
from cashu.wallet.wallet import Wallet as Wallet
|
||||||
|
from cashu.core.base import Proof
|
||||||
|
|
||||||
|
|
||||||
|
async def verify_mints(ctx, dtoken):
|
||||||
|
trust_token_mints = True
|
||||||
|
for mint_id in dtoken.get("mints"):
|
||||||
|
for keyset in set(dtoken["mints"][mint_id]["ks"]):
|
||||||
|
mint_url = dtoken["mints"][mint_id]["url"]
|
||||||
|
# init a temporary wallet object
|
||||||
|
keyset_wallet = Wallet(
|
||||||
|
mint_url, os.path.join(CASHU_DIR, ctx.obj["WALLET_NAME"])
|
||||||
|
)
|
||||||
|
# make sure that this mint indeed supports this keyset
|
||||||
|
mint_keysets = await keyset_wallet._get_keysets(mint_url)
|
||||||
|
assert keyset in mint_keysets["keysets"], "mint does not have this keyset."
|
||||||
|
|
||||||
|
# we validate the keyset id by fetching the keys from the mint
|
||||||
|
mint_keyset = await keyset_wallet._get_keyset(mint_url, keyset)
|
||||||
|
assert keyset == mint_keyset.id, Exception("keyset not valid.")
|
||||||
|
|
||||||
|
# we check the db whether we know this keyset already and ask the user
|
||||||
|
mint_keysets = await get_keyset(id=keyset, db=keyset_wallet.db)
|
||||||
|
if mint_keysets is None:
|
||||||
|
# we encountered a new mint and ask for a user confirmation
|
||||||
|
trust_token_mints = False
|
||||||
|
print("")
|
||||||
|
print("Warning: Tokens are from a mint or keyset you don't know yet.")
|
||||||
|
print("\n")
|
||||||
|
print(f"Mint URL: {mint_url}")
|
||||||
|
print(f"Mint keyset: {keyset}")
|
||||||
|
print("\n")
|
||||||
|
click.confirm(
|
||||||
|
f"Do you want to trust this mint and receive the tokens?",
|
||||||
|
abort=True,
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
trust_token_mints = True
|
||||||
|
|
||||||
|
assert trust_token_mints, Exception("Aborted!")
|
||||||
|
|
||||||
|
|
||||||
|
async def redeem_multimint(ctx, dtoken, script, signature):
|
||||||
|
# we get the mint information in the token and load the keys of each mint
|
||||||
|
# we then redeem the tokens for each keyset individually
|
||||||
|
for mint_id in dtoken.get("mints"):
|
||||||
|
for keyset in set(dtoken["mints"][mint_id]["ks"]):
|
||||||
|
mint_url = dtoken["mints"][mint_id]["url"]
|
||||||
|
# init a temporary wallet object
|
||||||
|
keyset_wallet = Wallet(
|
||||||
|
mint_url, os.path.join(CASHU_DIR, ctx.obj["WALLET_NAME"])
|
||||||
|
)
|
||||||
|
|
||||||
|
# load the keys
|
||||||
|
await keyset_wallet.load_mint(keyset_id=keyset)
|
||||||
|
|
||||||
|
# redeem proofs of this keyset
|
||||||
|
redeem_proofs = [
|
||||||
|
Proof(**p) for p in dtoken["tokens"] if Proof(**p).id == keyset
|
||||||
|
]
|
||||||
|
_, _ = await keyset_wallet.redeem(
|
||||||
|
redeem_proofs, scnd_script=script, scnd_siganture=signature
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user