feat: early multimint support

This commit is contained in:
callebtc
2022-12-24 01:53:58 +01:00
parent ca63e85e9e
commit bea17fbd1a
5 changed files with 198 additions and 44 deletions

View File

@@ -36,6 +36,7 @@ from cashu.wallet.crud import (
get_lightning_invoices,
get_reserved_proofs,
get_unused_locks,
get_keyset,
)
from cashu.wallet.wallet import Wallet as Wallet
@@ -64,14 +65,6 @@ class NaturalOrderGroup(click.Group):
)
@click.pass_context
def cli(ctx, host: str, walletname: str):
# configure logger
logger.remove()
logger.add(sys.stderr, level="DEBUG" if DEBUG else "INFO")
ctx.ensure_object(dict)
ctx.obj["HOST"] = host
ctx.obj["WALLET_NAME"] = walletname
wallet = Wallet(ctx.obj["HOST"], os.path.join(CASHU_DIR, walletname))
if TOR and not TorProxy().check_platform():
error_str = "Your settings say TOR=true but the built-in Tor bundle is not supported on your system. Please install Tor manually and set TOR=false and SOCKS_HOST=localhost and SOCKS_PORT=9050 in your Cashu config (recommended) or turn off Tor by setting TOR=false (not recommended). Cashu will not work until you edit your config file accordingly."
error_str += "\n\n"
@@ -83,6 +76,13 @@ def cli(ctx, host: str, walletname: str):
)
raise Exception(error_str)
# configure logger
logger.remove()
logger.add(sys.stderr, level="DEBUG" if DEBUG else "INFO")
ctx.ensure_object(dict)
ctx.obj["HOST"] = host
ctx.obj["WALLET_NAME"] = walletname
wallet = Wallet(ctx.obj["HOST"], os.path.join(CASHU_DIR, walletname))
ctx.obj["WALLET"] = wallet
asyncio.run(init_wallet(wallet))
pass
@@ -185,13 +185,22 @@ async def invoice(ctx, amount: int, hash: str):
@coro
async def balance(ctx, verbose):
wallet: Wallet = ctx.obj["WALLET"]
keyset_balances = wallet.balance_per_keyset()
if len(keyset_balances) > 1:
print(f"You have balances in {len(keyset_balances)} keysets:")
# keyset_balances = wallet.balance_per_keyset()
# if len(keyset_balances) > 1:
# print(f"You have balances in {len(keyset_balances)} keysets:")
# print("")
# for k, v in keyset_balances.items():
# print(
# f"Keyset: {k or 'undefined'} Balance: {v['balance']} sat (available: {v['available']} sat)"
# )
# print("")
mint_balances = await wallet.balance_per_minturl()
if len(mint_balances) > 1:
print(f"You have balances in {len(mint_balances)} mints:")
print("")
for k, v in keyset_balances.items():
for k, v in mint_balances.items():
print(
f"Keyset: {k or 'undefined'} Balance: {v['balance']} sat (available: {v['available']} sat)"
f"Mint: {k or 'undefined'} Balance: {v['balance']} sat (available: {v['available']} sat)"
)
print("")
if verbose:
@@ -221,9 +230,10 @@ async def send(ctx, amount: int, lock: str):
wallet.proofs, amount, lock, set_reserved=True
)
token = await wallet.serialize_proofs(
send_proofs, hide_secrets=True if lock and not p2sh else False
send_proofs,
hide_secrets=True if lock and not p2sh else False,
include_mints=True,
)
print(token)
wallet.status()
@@ -249,8 +259,62 @@ async def receive(ctx, token: str, lock: str):
signature = p2shscripts[0].signature
else:
script, signature = None, None
proofs = [Proof(**p) for p in json.loads(base64.urlsafe_b64decode(token))]
_, _ = await wallet.redeem(proofs, scnd_script=script, scnd_siganture=signature)
try:
# backwards compatibility < 0.7.0: tokens without mint information
proofs = [Proof(**p) for p in json.loads(base64.urlsafe_b64decode(token))]
_, _ = await wallet.redeem(proofs, scnd_script=script, scnd_siganture=signature)
except:
dtoken = json.loads(base64.urlsafe_b64decode(token))
assert "tokens" in dtoken, Exception("no proofs in 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 then redeem the tokens for each keyset individually
if "mints" in dtoken:
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"])
)
# 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()
else:
# no mint information present, assume default mint
proofs = [Proof(**p) for p in dtoken["tokens"]]
_, _ = await wallet.redeem(
proofs, scnd_script=script, scnd_siganture=signature
)
wallet.status()