mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 02:24:20 +01:00
use tokenObj in burn (#156)
* use tokenObj in burn * refactor token serialization * add tests * rename
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import base64
|
||||||
|
import json
|
||||||
from sqlite3 import Row
|
from sqlite3 import Row
|
||||||
from typing import Any, Dict, List, Optional, TypedDict, Union
|
from typing import Any, Dict, List, Optional, TypedDict, Union
|
||||||
|
|
||||||
@@ -357,3 +359,37 @@ class TokenV3(BaseModel):
|
|||||||
if self.memo:
|
if self.memo:
|
||||||
return_dict.update(dict(memo=self.memo)) # type: ignore
|
return_dict.update(dict(memo=self.memo)) # type: ignore
|
||||||
return return_dict
|
return return_dict
|
||||||
|
|
||||||
|
def get_proofs(self):
|
||||||
|
return [proof for token in self.token for proof in token.proofs]
|
||||||
|
|
||||||
|
def get_amount(self):
|
||||||
|
return sum([p.amount for p in self.get_proofs()])
|
||||||
|
|
||||||
|
def get_keysets(self):
|
||||||
|
return list(set([p.id for p in self.get_proofs()]))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def deserialize(cls, tokenv3_serialized: str):
|
||||||
|
"""
|
||||||
|
Takes a TokenV3 and serializes it as "cashuA<json_urlsafe_base64>.
|
||||||
|
"""
|
||||||
|
prefix = "cashuA"
|
||||||
|
assert tokenv3_serialized.startswith(prefix), Exception(
|
||||||
|
f"Token prefix not valid. Expected {prefix}."
|
||||||
|
)
|
||||||
|
token_base64 = tokenv3_serialized[len(prefix) :]
|
||||||
|
token = json.loads(base64.urlsafe_b64decode(token_base64))
|
||||||
|
return cls.parse_obj(token)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
"""
|
||||||
|
Takes a TokenV3 and serializes it as "cashuA<json_urlsafe_base64>.
|
||||||
|
"""
|
||||||
|
prefix = "cashuA"
|
||||||
|
tokenv3_serialized = prefix
|
||||||
|
# encode the token as a base64 string
|
||||||
|
tokenv3_serialized += base64.urlsafe_b64encode(
|
||||||
|
json.dumps(self.to_dict()).encode()
|
||||||
|
).decode()
|
||||||
|
return tokenv3_serialized
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import click
|
|||||||
from click import Context
|
from click import Context
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from cashu.core.base import Proof, TokenV1, TokenV2
|
from cashu.core.base import Proof, TokenV1, TokenV2, TokenV3
|
||||||
from cashu.core.helpers import sum_proofs
|
from cashu.core.helpers import sum_proofs
|
||||||
from cashu.core.migrations import migrate_databases
|
from cashu.core.migrations import migrate_databases
|
||||||
from cashu.core.settings import settings
|
from cashu.core.settings import settings
|
||||||
@@ -342,8 +342,7 @@ async def receive(ctx: Context, token: str, lock: str):
|
|||||||
# ----- receive token -----
|
# ----- receive token -----
|
||||||
|
|
||||||
# deserialize token
|
# deserialize token
|
||||||
# dtoken = json.loads(base64.urlsafe_b64decode(token))
|
tokenObj = TokenV3.deserialize(token)
|
||||||
tokenObj = wallet._deserialize_token_V3(token)
|
|
||||||
|
|
||||||
# tokenObj = TokenV2.parse_obj(dtoken)
|
# tokenObj = TokenV2.parse_obj(dtoken)
|
||||||
assert len(tokenObj.token), Exception("no proofs in token")
|
assert len(tokenObj.token), Exception("no proofs in token")
|
||||||
@@ -457,9 +456,8 @@ async def burn(ctx: Context, token: str, all: bool, force: bool, delete: str):
|
|||||||
proofs = [proof for proof in reserved_proofs if proof["send_id"] == delete]
|
proofs = [proof for proof in reserved_proofs if proof["send_id"] == delete]
|
||||||
else:
|
else:
|
||||||
# check only the specified ones
|
# check only the specified ones
|
||||||
proofs = [
|
tokenObj = TokenV3.deserialize(token)
|
||||||
Proof(**p) for p in json.loads(base64.urlsafe_b64decode(token))["proofs"]
|
proofs = tokenObj.get_proofs()
|
||||||
]
|
|
||||||
|
|
||||||
if delete:
|
if delete:
|
||||||
await wallet.invalidate(proofs, check_spendable=False)
|
await wallet.invalidate(proofs, check_spendable=False)
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ async def serialize_TokenV2_to_TokenV3(wallet: Wallet, tokenv2: TokenV2):
|
|||||||
tokenv3 = TokenV3(token=[TokenV3Token(proofs=tokenv2.proofs)])
|
tokenv3 = TokenV3(token=[TokenV3Token(proofs=tokenv2.proofs)])
|
||||||
if tokenv2.mints:
|
if tokenv2.mints:
|
||||||
tokenv3.token[0].mint = tokenv2.mints[0].url
|
tokenv3.token[0].mint = tokenv2.mints[0].url
|
||||||
token_serialized = await wallet._serialize_token_V3(tokenv3)
|
token_serialized = tokenv3.serialize()
|
||||||
return token_serialized
|
return token_serialized
|
||||||
|
|
||||||
|
|
||||||
@@ -248,5 +248,5 @@ async def serialize_TokenV1_to_TokenV3(wallet: Wallet, tokenv1: TokenV1):
|
|||||||
TokenV3: TokenV3
|
TokenV3: TokenV3
|
||||||
"""
|
"""
|
||||||
tokenv3 = TokenV3(token=[TokenV3Token(proofs=tokenv1.__root__)])
|
tokenv3 = TokenV3(token=[TokenV3Token(proofs=tokenv1.__root__)])
|
||||||
token_serialized = await wallet._serialize_token_V3(tokenv3)
|
token_serialized = tokenv3.serialize()
|
||||||
return token_serialized
|
return token_serialized
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ from cashu.core.script import (
|
|||||||
step1_carol_create_p2sh_address,
|
step1_carol_create_p2sh_address,
|
||||||
step2_carol_sign_tx,
|
step2_carol_sign_tx,
|
||||||
)
|
)
|
||||||
from cashu.core.secp import PublicKey
|
from cashu.core.secp import PrivateKey, PublicKey
|
||||||
from cashu.core.settings import settings
|
from cashu.core.settings import settings
|
||||||
from cashu.core.split import amount_split
|
from cashu.core.split import amount_split
|
||||||
from cashu.tor.tor import TorProxy
|
from cashu.tor.tor import TorProxy
|
||||||
@@ -111,7 +111,7 @@ class LedgerAPI:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def _construct_proofs(
|
def _construct_proofs(
|
||||||
self, promises: List[BlindedSignature], secrets: List[str], rs: List[str]
|
self, promises: List[BlindedSignature], secrets: List[str], rs: List[PrivateKey]
|
||||||
):
|
):
|
||||||
"""Returns proofs of promise from promises. Wants secrets and blinding factors rs."""
|
"""Returns proofs of promise from promises. Wants secrets and blinding factors rs."""
|
||||||
proofs: List[Proof] = []
|
proofs: List[Proof] = []
|
||||||
@@ -199,7 +199,7 @@ class LedgerAPI:
|
|||||||
secrets
|
secrets
|
||||||
), f"len(amounts)={len(amounts)} not equal to len(secrets)={len(secrets)}"
|
), f"len(amounts)={len(amounts)} not equal to len(secrets)={len(secrets)}"
|
||||||
outputs: List[BlindedMessage] = []
|
outputs: List[BlindedMessage] = []
|
||||||
rs = []
|
rs: List[PrivateKey] = []
|
||||||
for secret, amount in zip(secrets, amounts):
|
for secret, amount in zip(secrets, amounts):
|
||||||
B_, r = b_dhke.step1_alice(secret)
|
B_, r = b_dhke.step1_alice(secret)
|
||||||
rs.append(r)
|
rs.append(r)
|
||||||
@@ -684,30 +684,6 @@ class Wallet(LedgerAPI):
|
|||||||
token.token.append(token_proofs)
|
token.token.append(token_proofs)
|
||||||
return token
|
return token
|
||||||
|
|
||||||
async def _serialize_token_V3(self, token: TokenV3):
|
|
||||||
"""
|
|
||||||
Takes a TokenV3 and serializes it as "cashuA<json_urlsafe_base64>.
|
|
||||||
"""
|
|
||||||
prefix = "cashuA"
|
|
||||||
tokenv3_serialized = prefix
|
|
||||||
# encode the token as a base64 string
|
|
||||||
tokenv3_serialized += base64.urlsafe_b64encode(
|
|
||||||
json.dumps(token.to_dict()).encode()
|
|
||||||
).decode()
|
|
||||||
return tokenv3_serialized
|
|
||||||
|
|
||||||
def _deserialize_token_V3(self, tokenv3_serialized: str) -> TokenV3:
|
|
||||||
"""
|
|
||||||
Takes a TokenV3 and serializes it as "cashuA<json_urlsafe_base64>.
|
|
||||||
"""
|
|
||||||
prefix = "cashuA"
|
|
||||||
assert tokenv3_serialized.startswith(prefix), Exception(
|
|
||||||
f"Token prefix not valid. Expected {prefix}."
|
|
||||||
)
|
|
||||||
token_base64 = tokenv3_serialized[len(prefix) :]
|
|
||||||
token = json.loads(base64.urlsafe_b64decode(token_base64))
|
|
||||||
return TokenV3.parse_obj(token)
|
|
||||||
|
|
||||||
async def serialize_proofs(
|
async def serialize_proofs(
|
||||||
self, proofs: List[Proof], include_mints=True, legacy=False
|
self, proofs: List[Proof], include_mints=True, legacy=False
|
||||||
):
|
):
|
||||||
@@ -728,7 +704,7 @@ class Wallet(LedgerAPI):
|
|||||||
|
|
||||||
# V3 tokens
|
# V3 tokens
|
||||||
token = await self._make_token(proofs, include_mints)
|
token = await self._make_token(proofs, include_mints)
|
||||||
return await self._serialize_token_V3(token)
|
return token.serialize()
|
||||||
|
|
||||||
async def _make_token_v2(self, proofs: List[Proof], include_mints=True):
|
async def _make_token_v2(self, proofs: List[Proof], include_mints=True):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
|
from cashu.core.base import TokenV3
|
||||||
from cashu.core.split import amount_split
|
from cashu.core.split import amount_split
|
||||||
|
|
||||||
|
|
||||||
def test_get_output_split():
|
def test_get_output_split():
|
||||||
assert amount_split(13) == [1, 4, 8]
|
assert amount_split(13) == [1, 4, 8]
|
||||||
|
|
||||||
|
|
||||||
|
def test_tokenv3_get_amount():
|
||||||
|
token_str = "cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIkplaFpMVTZuQ3BSZCIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogIjBFN2lDazRkVmxSZjVQRjFnNFpWMnciLCAiQyI6ICIwM2FiNTgwYWQ5NTc3OGVkNTI5NmY4YmVlNjU1ZGJkN2Q2NDJmNWQzMmRlOGUyNDg0NzdlMGI0ZDZhYTg2M2ZjZDUifSwgeyJpZCI6ICJKZWhaTFU2bkNwUmQiLCAiYW1vdW50IjogOCwgInNlY3JldCI6ICJzNklwZXh3SGNxcXVLZDZYbW9qTDJnIiwgIkMiOiAiMDIyZDAwNGY5ZWMxNmE1OGFkOTAxNGMyNTliNmQ2MTRlZDM2ODgyOWYwMmMzODc3M2M0NzIyMWY0OTYxY2UzZjIzIn1dLCAibWludCI6ICJodHRwOi8vbG9jYWxob3N0OjMzMzgifV19"
|
||||||
|
token = TokenV3.deserialize(token_str)
|
||||||
|
assert token.get_amount() == 10
|
||||||
|
|
||||||
|
|
||||||
|
def test_tokenv3_get_proofs():
|
||||||
|
token_str = "cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIkplaFpMVTZuQ3BSZCIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogIjBFN2lDazRkVmxSZjVQRjFnNFpWMnciLCAiQyI6ICIwM2FiNTgwYWQ5NTc3OGVkNTI5NmY4YmVlNjU1ZGJkN2Q2NDJmNWQzMmRlOGUyNDg0NzdlMGI0ZDZhYTg2M2ZjZDUifSwgeyJpZCI6ICJKZWhaTFU2bkNwUmQiLCAiYW1vdW50IjogOCwgInNlY3JldCI6ICJzNklwZXh3SGNxcXVLZDZYbW9qTDJnIiwgIkMiOiAiMDIyZDAwNGY5ZWMxNmE1OGFkOTAxNGMyNTliNmQ2MTRlZDM2ODgyOWYwMmMzODc3M2M0NzIyMWY0OTYxY2UzZjIzIn1dLCAibWludCI6ICJodHRwOi8vbG9jYWxob3N0OjMzMzgifV19"
|
||||||
|
token = TokenV3.deserialize(token_str)
|
||||||
|
assert len(token.get_proofs()) == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_tokenv3_deserialize_serialize():
|
||||||
|
token_str = "cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIkplaFpMVTZuQ3BSZCIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogIjBFN2lDazRkVmxSZjVQRjFnNFpWMnciLCAiQyI6ICIwM2FiNTgwYWQ5NTc3OGVkNTI5NmY4YmVlNjU1ZGJkN2Q2NDJmNWQzMmRlOGUyNDg0NzdlMGI0ZDZhYTg2M2ZjZDUifSwgeyJpZCI6ICJKZWhaTFU2bkNwUmQiLCAiYW1vdW50IjogOCwgInNlY3JldCI6ICJzNklwZXh3SGNxcXVLZDZYbW9qTDJnIiwgIkMiOiAiMDIyZDAwNGY5ZWMxNmE1OGFkOTAxNGMyNTliNmQ2MTRlZDM2ODgyOWYwMmMzODc3M2M0NzIyMWY0OTYxY2UzZjIzIn1dLCAibWludCI6ICJodHRwOi8vbG9jYWxob3N0OjMzMzgifV19"
|
||||||
|
token = TokenV3.deserialize(token_str)
|
||||||
|
assert token.serialize() == token_str
|
||||||
|
|||||||
Reference in New Issue
Block a user