Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 120 additions & 11 deletions cashu/wallet/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ async def pay(
print(f"Amount: {wallet.unit.str(pr.a)} ({pr.a} {pr.u})")

if pr.m and wallet.url not in pr.m:
print(f"Error: Current mint {wallet.url} is not accepted by the receiver.")
print(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated change.

f"Error: Current mint {wallet.url} is not accepted by the receiver.")
print(f"Accepted mints: {pr.m}")
return

Expand Down Expand Up @@ -364,7 +365,8 @@ async def pay(
if post_transports:
transport = post_transports[0]
url = transport.a
print(f"Sending token via POST to {url}...", end="", flush=True)
print(
f"Sending token via POST to {url}...", end="", flush=True)

token_obj = deserialize_token_from_string(token)
assert isinstance(
Expand Down Expand Up @@ -509,12 +511,13 @@ async def invoice(
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_mint()
await print_balance(ctx)
amount = int(amount * 100) if wallet.unit in [Unit.usd, Unit.eur] else int(amount)
amount = int(
amount * 100) if wallet.unit in [Unit.usd, Unit.eur] else int(amount)
print(f"Requesting invoice for {wallet.unit.str(amount)}.")
# in case the user wants a specific split, we create a list of amounts
optional_split = None
if split:
assert amount % split == 0, "split must be divisor or amount"
assert amount % split == 0, "split must be divisor of amount"
assert amount >= split, "split must smaller or equal amount"
n_splits = amount // split
optional_split = [split] * n_splits
Expand Down Expand Up @@ -672,7 +675,8 @@ async def swap(ctx: Context):
if incoming_wallet.url == outgoing_wallet.url:
raise Exception("mints for swap have to be different")

amount = int(input(f"Enter amount to swap in {incoming_wallet.unit.name}: "))
amount = int(
input(f"Enter amount to swap in {incoming_wallet.unit.name}: "))
assert amount > 0, "amount is not positive"

# request invoice from incoming mint
Expand Down Expand Up @@ -731,7 +735,8 @@ async def balance(ctx: Context, verbose):
print("")
for i, (k, v) in enumerate(unit_balances.items()):
unit = k
print(f"Unit {i+1} ({unit}) - Balance: {unit.str(int(v['available']))}")
print(
f"Unit {i+1} ({unit}) - Balance: {unit.str(int(v['available']))}")
print("")
if verbose:
# show balances per keyset
Expand Down Expand Up @@ -832,7 +837,8 @@ async def send_command(
force_swap: bool,
):
wallet: Wallet = ctx.obj["WALLET"]
amount = int(amount * 100) if wallet.unit in [Unit.usd, Unit.eur] else int(amount)
amount = int(
amount * 100) if wallet.unit in [Unit.usd, Unit.eur] else int(amount)
await send(
wallet,
amount=amount,
Expand Down Expand Up @@ -1003,7 +1009,8 @@ async def pending(ctx: Context, legacy, number: int, offset: int):
reserved_proofs = await get_reserved_proofs(wallet.db)
if len(reserved_proofs):
print("--------------------------\n")
sorted_proofs = sorted(reserved_proofs, key=itemgetter("send_id"), reverse=True) # type: ignore
sorted_proofs = sorted(reserved_proofs, key=itemgetter(
"send_id"), reverse=True) # type: ignore
if number:
number += offset
for i, (key, value) in islice(
Expand Down Expand Up @@ -1045,6 +1052,105 @@ async def pending(ctx: Context, legacy, number: int, offset: int):
print("To receive all pending tokens use: cashu receive -a")


@cli.command("proofs", help="List raw proofs in wallet.")
@click.option(
"--all", "-a", default=False, is_flag=True, help="Include reserved proofs."
)
@click.option(
"--no-dleq", default=False, is_flag=True, help="Do not include DLEQ proofs."
)
@click.option(
"--indent",
"-i",
default=2,
help="Number of spaces to indent JSON with.",
type=int,
)
@click.option(
"--keyset",
"-k",
default=None,
help="Filter by keyset ID.",
type=str,
)
@click.option(
"--order",
"-o",
default=None,
help="Sort the proofs by amount in ascending (asc) or descending (desc) order.",
type=str,
)
@click.pass_context
@coro
async def proofs(
ctx: Context, all: bool, no_dleq: bool, indent: int, keyset: str, order: str
):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_proofs()

# Get proofs based on --all flag
if all:
# Include both available and reserved proofs
proofs = wallet.proofs
else:
# Only include available (non-reserved) proofs
proofs = [p for p in wallet.proofs if not p.reserved]

# Filter by keyset if specified
if keyset:
proofs = [p for p in proofs if p.id == keyset]

if not proofs:
if keyset:
print(f"No proofs found for keyset: {keyset}")
else:
print("No proofs found.")
return

# Sort the proofs if ordering is specified.
if order is not None:
if order == "asc":
proofs = sorted(proofs, key=lambda p: p.amount)
elif order == "desc":
proofs = sorted(proofs, key=lambda p: p.amount, reverse=True)
else:
print(
f"Unidentified order argument: {order}. Valid arguments are 'asc' and 'desc'."
)
return

# Convert proofs to dictionary format
include_dleq = not no_dleq

proofs_dict = []
for proof in proofs:
proof_dict = {
"id": proof.id,
"amount": proof.amount,
"secret": proof.secret,
"C": proof.C,
}

if include_dleq and proof.dleq:
proof_dict["dleq"] = {
"e": proof.dleq.e,
"s": proof.dleq.s,
"r": proof.dleq.r,
}

if proof.witness:
proof_dict["witness"] = proof.witness

proofs_dict.append(proof_dict)

# Print as JSON
proofs_json = json.dumps(
proofs_dict,
indent=indent,
)
print(proofs_json)


@cli.group(cls=NaturalOrderGroup)
def lock():
"""Generate receiving locks."""
Expand Down Expand Up @@ -1317,7 +1423,8 @@ async def info(ctx: Context, mint: bool, mnemonic: bool, reload: bool):
if mint_info:
print(f" - Mint name: {mint_info['name']}")
if mint_info.get("description"):
print(f" - Description: {mint_info['description']}")
print(
f" - Description: {mint_info['description']}")
if mint_info.get("description_long"):
print(
f" - Long description: {mint_info['description_long']}"
Expand All @@ -1329,7 +1436,8 @@ async def info(ctx: Context, mint: bool, mnemonic: bool, reload: bool):
if mint_info.get("version"):
print(f" - Version: {mint_info['version']}")
if mint_info.get("motd"):
print(f" - Message of the day: {mint_info['motd']}")
print(
f" - Message of the day: {mint_info['motd']}")
if mint_info.get("time"):
print(f" - Server time: {mint_info['time']}")
if mint_info.get("nuts"):
Expand Down Expand Up @@ -1473,7 +1581,8 @@ async def auth(ctx: Context, mint: bool, force: bool, password: bool):

if mint:
new_proofs = await auth_wallet.mint_blind_auth()
print(f"Minted {auth_wallet.unit.str(sum_proofs(new_proofs))} auth tokens.")
print(
f"Minted {auth_wallet.unit.str(sum_proofs(new_proofs))} auth tokens.")


@cli.group(cls=NaturalOrderGroup)
Expand Down
Loading
Loading