mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 19:14:19 +01:00
tokens to coins
This commit is contained in:
@@ -65,7 +65,7 @@ def coro(f):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@cli.command("mint", help="Mint tokens.")
|
@cli.command("mint", help="Mint coins.")
|
||||||
@click.argument("amount", type=int)
|
@click.argument("amount", type=int)
|
||||||
@click.option("--hash", default="", help="Hash of the paid invoice.", type=str)
|
@click.option("--hash", default="", help="Hash of the paid invoice.", type=str)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@@ -99,9 +99,9 @@ async def balance(ctx):
|
|||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
|
||||||
@cli.command("send", help="Send tokens.")
|
@cli.command("send", help="Send coins.")
|
||||||
@click.argument("amount", type=int)
|
@click.argument("amount", type=int)
|
||||||
@click.option("--lock", "-l", default=None, help="Token lock (P2SH address).", type=str)
|
@click.option("--lock", "-l", default=None, help="Coin lock (P2SH address).", type=str)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@coro
|
@coro
|
||||||
async def send(ctx, amount: int, lock: str):
|
async def send(ctx, amount: int, lock: str):
|
||||||
@@ -116,21 +116,19 @@ async def send(ctx, amount: int, lock: str):
|
|||||||
wallet.status()
|
wallet.status()
|
||||||
_, send_proofs = await wallet.split_to_send(wallet.proofs, amount, lock)
|
_, send_proofs = await wallet.split_to_send(wallet.proofs, amount, lock)
|
||||||
await wallet.set_reserved(send_proofs, reserved=True)
|
await wallet.set_reserved(send_proofs, reserved=True)
|
||||||
token = await wallet.serialize_proofs(
|
coin = 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
|
||||||
)
|
)
|
||||||
print(token)
|
print(coin)
|
||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
|
||||||
@cli.command("receive", help="Receive tokens.")
|
@cli.command("receive", help="Receive coins.")
|
||||||
@click.argument("token", type=str)
|
@click.argument("coin", type=str)
|
||||||
# @click.option("--secret", "-s", default=None, help="Token secret.", type=str)
|
|
||||||
@click.option("--unlock", "-u", default=None, help="Unlock script.", type=str)
|
@click.option("--unlock", "-u", default=None, help="Unlock script.", type=str)
|
||||||
# @click.option("--signature", default=None, help="Script signature.", type=str)
|
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@coro
|
@coro
|
||||||
async def receive(ctx, token: str, unlock: str):
|
async def receive(ctx, coin: str, unlock: str):
|
||||||
wallet: Wallet = ctx.obj["WALLET"]
|
wallet: Wallet = ctx.obj["WALLET"]
|
||||||
wallet.load_mint()
|
wallet.load_mint()
|
||||||
wallet.status()
|
wallet.status()
|
||||||
@@ -140,55 +138,27 @@ async def receive(ctx, token: str, unlock: str):
|
|||||||
), "unlock format wrong, expected <script>:<signature>"
|
), "unlock format wrong, expected <script>:<signature>"
|
||||||
script = unlock.split(":")[0]
|
script = unlock.split(":")[0]
|
||||||
signature = unlock.split(":")[1]
|
signature = unlock.split(":")[1]
|
||||||
proofs = [Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(token))]
|
else:
|
||||||
|
script, signature = None, None
|
||||||
|
proofs = [Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(coin))]
|
||||||
_, _ = await wallet.redeem(proofs, snd_script=script, snd_siganture=signature)
|
_, _ = await wallet.redeem(proofs, snd_script=script, snd_siganture=signature)
|
||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
|
||||||
@cli.command("address", help="Generate receiving address.")
|
@cli.command("burn", help="Burn spent coins.")
|
||||||
@click.pass_context
|
@click.argument("coin", required=False, type=str)
|
||||||
@coro
|
@click.option("--all", "-a", default=False, is_flag=True, help="Burn all spent coins.")
|
||||||
async def address(ctx):
|
|
||||||
alice_privkey = step0_carol_privkey()
|
|
||||||
txin_redeemScript = step0_carol_checksig_redeemscrip(alice_privkey.pub)
|
|
||||||
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
|
|
||||||
# print("Redeem script:", txin_redeemScript.__repr__())
|
|
||||||
print("---- Pay to script hash (P2SH) ----\n")
|
|
||||||
print("You can use this address to receive tokens that only you can redeem.")
|
|
||||||
print("")
|
|
||||||
print(f"Public receiving address: P2SH:{txin_p2sh_address}")
|
|
||||||
print("")
|
|
||||||
print(
|
|
||||||
f"To send to this address:\n\ncashu send <amount> --lock P2SH:{txin_p2sh_address}"
|
|
||||||
)
|
|
||||||
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("!!! The command below is private. Do not share. Back it up. !!!")
|
|
||||||
print(
|
|
||||||
"If you lose this command (script and signature), you will not\nbe able to redeem tokens sent to this address!\n\n"
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"To receive:\n\ncashu receive <token> --unlock {txin_redeemScript_b64}:{txin_signature_b64}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("burn", help="Burn spent tokens.")
|
|
||||||
@click.argument("token", required=False, type=str)
|
|
||||||
@click.option("--all", "-a", default=False, is_flag=True, help="Burn all spent tokens.")
|
|
||||||
@click.option(
|
@click.option(
|
||||||
"--force", "-f", default=False, is_flag=True, help="Force check on all tokens."
|
"--force", "-f", default=False, is_flag=True, help="Force check on all coins."
|
||||||
)
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@coro
|
@coro
|
||||||
async def burn(ctx, token: str, all: bool, force: bool):
|
async def burn(ctx, coin: str, all: bool, force: bool):
|
||||||
wallet: Wallet = ctx.obj["WALLET"]
|
wallet: Wallet = ctx.obj["WALLET"]
|
||||||
wallet.load_mint()
|
wallet.load_mint()
|
||||||
if not (all or token or force) or (token and all):
|
if not (all or coin or force) or (coin and all):
|
||||||
print(
|
print(
|
||||||
"Error: enter a token or use --all to burn all pending tokens or --force to check all tokens."
|
"Error: enter a coin or use --all to burn all pending coins or --force to check all coins."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
if all:
|
if all:
|
||||||
@@ -200,14 +170,14 @@ async def burn(ctx, token: str, all: bool, force: bool):
|
|||||||
else:
|
else:
|
||||||
# check only the specified ones
|
# check only the specified ones
|
||||||
proofs = [
|
proofs = [
|
||||||
Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(token))
|
Proof.from_dict(p) for p in json.loads(base64.urlsafe_b64decode(coin))
|
||||||
]
|
]
|
||||||
wallet.status()
|
wallet.status()
|
||||||
await wallet.invalidate(proofs)
|
await wallet.invalidate(proofs)
|
||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
|
||||||
@cli.command("pending", help="Show pending tokens.")
|
@cli.command("pending", help="Show pending coins.")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@coro
|
@coro
|
||||||
async def pending(ctx):
|
async def pending(ctx):
|
||||||
@@ -221,8 +191,8 @@ async def pending(ctx):
|
|||||||
groupby(sorted_proofs, key=itemgetter("send_id"))
|
groupby(sorted_proofs, key=itemgetter("send_id"))
|
||||||
):
|
):
|
||||||
grouped_proofs = list(value)
|
grouped_proofs = list(value)
|
||||||
token = await wallet.serialize_proofs(grouped_proofs)
|
coin = await wallet.serialize_proofs(grouped_proofs)
|
||||||
token_hidden_secret = await wallet.serialize_proofs(
|
coin_hidden_secret = await wallet.serialize_proofs(
|
||||||
grouped_proofs, hide_secrets=True
|
grouped_proofs, hide_secrets=True
|
||||||
)
|
)
|
||||||
reserved_date = datetime.utcfromtimestamp(
|
reserved_date = datetime.utcfromtimestamp(
|
||||||
@@ -231,12 +201,12 @@ async def pending(ctx):
|
|||||||
print(
|
print(
|
||||||
f"#{i} Amount: {sum([p['amount'] for p in grouped_proofs])} sat Time: {reserved_date} ID: {key}\n"
|
f"#{i} Amount: {sum([p['amount'] for p in grouped_proofs])} sat Time: {reserved_date} ID: {key}\n"
|
||||||
)
|
)
|
||||||
print(f"With secret: {token}\n\nSecretless: {token_hidden_secret}\n")
|
print(f"With secret: {coin}\n\nSecretless: {coin_hidden_secret}\n")
|
||||||
print(f"--------------------------\n")
|
print(f"--------------------------\n")
|
||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
|
||||||
@cli.command("pay", help="Pay lightning invoice.")
|
@cli.command("pay", help="Pay Lightning invoice.")
|
||||||
@click.argument("invoice", type=str)
|
@click.argument("invoice", type=str)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@coro
|
@coro
|
||||||
@@ -260,6 +230,35 @@ async def pay(ctx, invoice: str):
|
|||||||
wallet.status()
|
wallet.status()
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command("address", help="Generate receiving address.")
|
||||||
|
@click.pass_context
|
||||||
|
@coro
|
||||||
|
async def address(ctx):
|
||||||
|
alice_privkey = step0_carol_privkey()
|
||||||
|
txin_redeemScript = step0_carol_checksig_redeemscrip(alice_privkey.pub)
|
||||||
|
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
|
||||||
|
# print("Redeem script:", txin_redeemScript.__repr__())
|
||||||
|
print("---- Pay to script hash (P2SH) ----\n")
|
||||||
|
print("Use a lock to receive coins that only you can unlock.")
|
||||||
|
print("")
|
||||||
|
print(f"Public receiving address: P2SH:{txin_p2sh_address}")
|
||||||
|
print("")
|
||||||
|
print(
|
||||||
|
f"To send to this address:\n\ncashu send <amount> --lock P2SH:{txin_p2sh_address}"
|
||||||
|
)
|
||||||
|
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(
|
||||||
|
"!!! The command below is private. Do not share. You have to remember it. Do not lose. !!!\n"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"To receive:\n\ncashu receive <coin> --unlock {txin_redeemScript_b64}:{txin_signature_b64}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@cli.command("info", help="Information about Cashu wallet.")
|
@cli.command("info", help="Information about Cashu wallet.")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@coro
|
@coro
|
||||||
|
|||||||
@@ -246,20 +246,12 @@ class Wallet(LedgerAPI):
|
|||||||
async def redeem(
|
async def redeem(
|
||||||
self,
|
self,
|
||||||
proofs: List[Proof],
|
proofs: List[Proof],
|
||||||
# snd_secret: str = None,
|
|
||||||
snd_script: str = None,
|
snd_script: str = None,
|
||||||
snd_siganture: str = None,
|
snd_siganture: str = None,
|
||||||
):
|
):
|
||||||
# if snd_secret:
|
|
||||||
# logger.debug(f"Redeption secret: {snd_secret}")
|
|
||||||
# snd_secrets = self.generate_secrets(snd_secret, len(proofs))
|
|
||||||
# assert len(proofs) == len(snd_secrets)
|
|
||||||
# # overload proofs with custom secrets for redemption
|
|
||||||
# for p, s in zip(proofs, snd_secrets):
|
|
||||||
# p.secret = s
|
|
||||||
if snd_script and snd_siganture:
|
if snd_script and snd_siganture:
|
||||||
logger.debug(f"Unlock script: {snd_script}")
|
logger.debug(f"Unlock script: {snd_script}")
|
||||||
# overload proofs with unlock script
|
# attach unlock scripts to proofs
|
||||||
for p in proofs:
|
for p in proofs:
|
||||||
p.script = P2SHScript(script=snd_script, signature=snd_siganture)
|
p.script = P2SHScript(script=snd_script, signature=snd_siganture)
|
||||||
return await self.split(proofs, sum(p["amount"] for p in proofs))
|
return await self.split(proofs, sum(p["amount"] for p in proofs))
|
||||||
|
|||||||
Reference in New Issue
Block a user