diff --git a/cashu/core/base.py b/cashu/core/base.py index 7cc775d..6ab1de4 100644 --- a/cashu/core/base.py +++ b/cashu/core/base.py @@ -7,135 +7,6 @@ from cashu.core.crypto import derive_keys, derive_keyset_id, derive_pubkeys from cashu.core.secp import PrivateKey, PublicKey -class CashuError(BaseModel): - code = "000" - error = "CashuError" - - -class KeyBase(BaseModel): - id: str - amount: int - pubkey: str - - @classmethod - def from_row(cls, row: Row): - if row is None: - return cls - return cls( - id=row[0], - amount=int(row[1]), - pubkey=row[2], - ) - - -class WalletKeyset: - id: str - public_keys: Dict[int, PublicKey] - mint_url: Union[str, None] = None - valid_from: Union[str, None] = None - valid_to: Union[str, None] = None - first_seen: Union[str, None] = None - active: bool = True - - def __init__( - self, - pubkeys: Dict[int, PublicKey] = None, - mint_url=None, - id=None, - valid_from=None, - valid_to=None, - first_seen=None, - active=None, - ): - self.id = id - self.valid_from = valid_from - self.valid_to = valid_to - self.first_seen = first_seen - self.active = active - self.mint_url = mint_url - if pubkeys: - self.public_keys = pubkeys - self.id = derive_keyset_id(self.public_keys) - - @classmethod - def from_row(cls, row: Row): - if row is None: - return cls - return cls( - id=row[0], - mint_url=row[1], - valid_from=row[2], - valid_to=row[3], - first_seen=row[4], - active=row[5], - ) - - -class MintKeyset: - id: str - derivation_path: str - private_keys: Dict[int, PrivateKey] - public_keys: Dict[int, PublicKey] = None - valid_from: Union[str, None] = None - valid_to: Union[str, None] = None - first_seen: Union[str, None] = None - active: bool = True - - def __init__( - self, - id=None, - valid_from=None, - valid_to=None, - first_seen=None, - active=None, - seed: Union[None, str] = None, - derivation_path: str = "0", - ): - self.derivation_path = derivation_path - self.id = id - self.valid_from = valid_from - self.valid_to = valid_to - self.first_seen = first_seen - self.active = active - # generate keys from seed - if seed: - self.generate_keys(seed) - - def generate_keys(self, seed): - self.private_keys = derive_keys(seed, self.derivation_path) - self.public_keys = derive_pubkeys(self.private_keys) - self.id = derive_keyset_id(self.public_keys) - - @classmethod - def from_row(cls, row: Row): - if row is None: - return cls - return cls( - id=row[0], - derivation_path=row[1], - valid_from=row[2], - valid_to=row[3], - first_seen=row[4], - active=row[5], - ) - - def get_keybase(self): - return { - k: KeyBase(id=self.id, amount=k, pubkey=v.serialize().hex()) - for k, v in self.public_keys.items() - } - - -class MintKeysets: - keysets: Dict[str, MintKeyset] - - def __init__(self, keysets: List[MintKeyset]): - self.keysets: Dict[str, MintKeyset] = {k.id: k for k in keysets} - - def get_ids(self): - return [k for k, _ in self.keysets.items()] - - class P2SHScript(BaseModel): script: str signature: str @@ -297,3 +168,127 @@ class MeltRequest(BaseModel): proofs: List[Proof] amount: int = None # deprecated invoice: str + + +class KeyBase(BaseModel): + id: str + amount: int + pubkey: str + + @classmethod + def from_row(cls, row: Row): + if row is None: + return cls + return cls( + id=row[0], + amount=int(row[1]), + pubkey=row[2], + ) + + +class WalletKeyset: + id: str + public_keys: Dict[int, PublicKey] + mint_url: Union[str, None] = None + valid_from: Union[str, None] = None + valid_to: Union[str, None] = None + first_seen: Union[str, None] = None + active: bool = True + + def __init__( + self, + pubkeys: Dict[int, PublicKey] = None, + mint_url=None, + id=None, + valid_from=None, + valid_to=None, + first_seen=None, + active=None, + ): + self.id = id + self.valid_from = valid_from + self.valid_to = valid_to + self.first_seen = first_seen + self.active = active + self.mint_url = mint_url + if pubkeys: + self.public_keys = pubkeys + self.id = derive_keyset_id(self.public_keys) + + @classmethod + def from_row(cls, row: Row): + if row is None: + return cls + return cls( + id=row[0], + mint_url=row[1], + valid_from=row[2], + valid_to=row[3], + first_seen=row[4], + active=row[5], + ) + + +class MintKeyset: + id: str + derivation_path: str + private_keys: Dict[int, PrivateKey] + public_keys: Dict[int, PublicKey] = None + valid_from: Union[str, None] = None + valid_to: Union[str, None] = None + first_seen: Union[str, None] = None + active: bool = True + + def __init__( + self, + id=None, + valid_from=None, + valid_to=None, + first_seen=None, + active=None, + seed: Union[None, str] = None, + derivation_path: str = "0", + ): + self.derivation_path = derivation_path + self.id = id + self.valid_from = valid_from + self.valid_to = valid_to + self.first_seen = first_seen + self.active = active + # generate keys from seed + if seed: + self.generate_keys(seed) + + def generate_keys(self, seed): + self.private_keys = derive_keys(seed, self.derivation_path) + self.public_keys = derive_pubkeys(self.private_keys) + self.id = derive_keyset_id(self.public_keys) + + @classmethod + def from_row(cls, row: Row): + if row is None: + return cls + return cls( + id=row[0], + derivation_path=row[1], + valid_from=row[2], + valid_to=row[3], + first_seen=row[4], + active=row[5], + ) + + def get_keybase(self): + return { + k: KeyBase(id=self.id, amount=k, pubkey=v.serialize().hex()) + for k, v in self.public_keys.items() + } + + +class MintKeysets: + keysets: Dict[str, MintKeyset] + + def __init__(self, keysets: List[MintKeyset]): + self.keysets: Dict[str, MintKeyset] = {k.id: k for k in keysets} + + def get_ids(self): + return [k for k, _ in self.keysets.items()] diff --git a/cashu/core/crypto.py b/cashu/core/crypto.py index 76255f0..15a8023 100644 --- a/cashu/core/crypto.py +++ b/cashu/core/crypto.py @@ -1,6 +1,6 @@ import hashlib from typing import Dict, List - +import base64 from cashu.core.secp import PrivateKey, PublicKey from cashu.core.settings import MAX_ORDER @@ -29,4 +29,6 @@ def derive_pubkeys(keys: Dict[int, PrivateKey]): def derive_keyset_id(keys: Dict[str, PublicKey]): """Deterministic derivation keyset_id from set of public keys.""" pubkeys_concat = "".join([p.serialize().hex() for _, p in keys.items()]) - return hashlib.sha256((pubkeys_concat).encode("utf-8")).hexdigest()[:16] + return base64.b64encode(hashlib.sha256((pubkeys_concat).encode("utf-8")).digest())[ + :12 + ] diff --git a/cashu/core/errors.py b/cashu/core/errors.py index a2ea6c3..f770896 100644 --- a/cashu/core/errors.py +++ b/cashu/core/errors.py @@ -1,21 +1,26 @@ from pydantic import BaseModel -class CashuError(Exception, BaseModel): +class CashuError(BaseModel): code = "000" error = "CashuError" -class MintException(CashuError): - code = 100 - error = "Mint" +# class CashuError(Exception, BaseModel): +# code = "000" +# error = "CashuError" -class LightningException(MintException): - code = 200 - error = "Lightning" +# class MintException(CashuError): +# code = 100 +# error = "Mint" -class InvoiceNotPaidException(LightningException): - code = 201 - error = "invoice not paid." +# class LightningException(MintException): +# code = 200 +# error = "Lightning" + + +# class InvoiceNotPaidException(LightningException): +# code = 201 +# error = "invoice not paid." diff --git a/cashu/mint/router.py b/cashu/mint/router.py index a502398..e7842d7 100644 --- a/cashu/mint/router.py +++ b/cashu/mint/router.py @@ -4,7 +4,6 @@ from fastapi import APIRouter from secp256k1 import PublicKey from cashu.core.base import ( - CashuError, CheckFeesRequest, CheckFeesResponse, CheckRequest, @@ -15,6 +14,8 @@ from cashu.core.base import ( PostSplitResponse, SplitRequest, ) +from cashu.core.errors import CashuError + from cashu.mint import ledger router: APIRouter = APIRouter()