Skip to content

Commit

Permalink
Merge branch 'main' into add-fees-merge-main
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed May 23, 2024
2 parents 80fc53e + 61cf7de commit a0614fe
Show file tree
Hide file tree
Showing 32 changed files with 509 additions and 124 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Docker Build

on:
release:
types: [published]
types: [released]

jobs:
build-and-push:
Expand Down Expand Up @@ -42,7 +42,7 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name == 'release' }}
push: ${{ github.event_name == 'release' && github.event.action == 'released' }}
tags: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.get_tag.outputs.tag }}
platforms: linux/amd64,linux/arm64
cache-from: type=local,src=/tmp/.buildx-cache
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pypi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Pip package
on:
push:
release:
types: [published]
types: [released]

jobs:
build-and-push:
Expand All @@ -30,6 +30,6 @@ jobs:
pip install --upgrade dist/*.whl
- name: Upload to PyPI on release
if: github.event_name == 'release'
if: github.event_name == 'release' && github.event.action == 'released'
run: |
poetry publish -u __token__ -p ${{ secrets.PYPI_API_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/regtest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ jobs:
MINT_LND_REST_ENDPOINT: https://localhost:8081/
MINT_LND_REST_CERT: ./regtest/data/lnd-3/tls.cert
MINT_LND_REST_MACAROON: ./regtest/data/lnd-3/data/chain/bitcoin/regtest/admin.macaroon
MINT_LND_ENABLE_MPP: true
# LND_GRPC_ENDPOINT: localhost
# LND_GRPC_PORT: 10009
# LND_GRPC_CERT: ./regtest/data/lnd-3/tls.cert
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ vim .env
To use the wallet with the [public test mint](#test-instance), you need to change the appropriate entries in the `.env` file.

#### Test instance
*Warning: this instance is just for demonstration only. The server could vanish at any moment so consider any Satoshis you deposit a donation.*
*Warning: this instance is just for demonstration purposes and development only. The satoshis are not real.*

Change the appropriate `.env` file settings to
```bash
MINT_URL=https://8333.space:3338
MINT_URL=https://testnut.cashu.space
```

# Using Cashu
Expand Down
32 changes: 17 additions & 15 deletions cashu/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,18 @@ def htlcpreimage(self) -> Union[str, None]:
return HTLCWitness.from_witness(self.witness).preimage


class Proofs(BaseModel):
# NOTE: not used in Pydantic validation
__root__: List[Proof]


class BlindedMessage(BaseModel):
"""
Blinded message or blinded secret or "output" which is to be signed by the mint
"""

amount: int
id: str
id: str # Keyset id
B_: str # Hex-encoded blinded message
witness: Union[str, None] = None # witnesses (used for P2PK with SIG_ALL)

Expand All @@ -192,10 +197,14 @@ def p2pksigs(self) -> List[str]:


class BlindedMessage_Deprecated(BaseModel):
# Same as BlindedMessage, but without the id field
"""
Deprecated: BlindedMessage for v0 protocol (deprecated api routes) have no id field.
Blinded message or blinded secret or "output" which is to be signed by the mint
"""

amount: int
B_: str # Hex-encoded blinded message
id: Optional[str] = None
witness: Union[str, None] = None # witnesses (used for P2PK with SIG_ALL)

@property
Expand Down Expand Up @@ -491,6 +500,8 @@ class MintKeyset:
version: Optional[str] = None
input_fee_ppm: Optional[int] = None

duplicate_keyset_id: Optional[str] = None # BACKWARDS COMPATIBILITY < 0.15.0

def __init__(
self,
*,
Expand Down Expand Up @@ -573,12 +584,6 @@ def generate_keys(self):
assert self.seed, "seed not set"
assert self.derivation_path, "derivation path not set"

# we compute the keyset id from the public keys only if it is not
# loaded from the database. This is to allow for backwards compatibility
# with old keysets with new id's and vice versa. This code can be removed
# if there are only new keysets in the mint (> 0.15.0)
id_in_db = self.id

if self.version_tuple < (0, 12):
# WARNING: Broken key derivation for backwards compatibility with < 0.12
self.private_keys = derive_keys_backwards_compatible_insecure_pre_0_12(
Expand All @@ -589,22 +594,19 @@ def generate_keys(self):
f"WARNING: Using weak key derivation for keyset {self.id} (backwards"
" compatibility < 0.12)"
)
# load from db or derive
self.id = id_in_db or derive_keyset_id_deprecated(self.public_keys) # type: ignore
self.id = derive_keyset_id_deprecated(self.public_keys) # type: ignore
elif self.version_tuple < (0, 15):
self.private_keys = derive_keys_sha256(self.seed, self.derivation_path)
logger.trace(
f"WARNING: Using non-bip32 derivation for keyset {self.id} (backwards"
" compatibility < 0.15)"
)
self.public_keys = derive_pubkeys(self.private_keys) # type: ignore
# load from db or derive
self.id = id_in_db or derive_keyset_id_deprecated(self.public_keys) # type: ignore
self.id = derive_keyset_id_deprecated(self.public_keys) # type: ignore
else:
self.private_keys = derive_keys(self.seed, self.derivation_path)
self.public_keys = derive_pubkeys(self.private_keys) # type: ignore
# load from db or derive
self.id = id_in_db or derive_keyset_id(self.public_keys) # type: ignore
self.id = derive_keyset_id(self.public_keys) # type: ignore


# ------- TOKEN -------
Expand Down
14 changes: 13 additions & 1 deletion cashu/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ class GetInfoResponse(BaseModel):
description_long: Optional[str] = None
contact: Optional[List[List[str]]] = None
motd: Optional[str] = None
nuts: Optional[Dict[int, Dict[str, Any]]] = None
nuts: Optional[Dict[int, Any]] = None


class Nut15MppSupport(BaseModel):
method: str
unit: str
mpp: bool


class GetInfoResponse_deprecated(BaseModel):
Expand Down Expand Up @@ -241,6 +247,12 @@ class PostRestoreRequest(BaseModel):
)


class PostRestoreRequest_Deprecated(BaseModel):
outputs: List[BlindedMessage_Deprecated] = Field(
..., max_items=settings.mint_max_request_length
)


class PostRestoreResponse(BaseModel):
outputs: List[BlindedMessage] = []
signatures: List[BlindedSignature] = []
Expand Down
11 changes: 9 additions & 2 deletions cashu/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class MintSettings(CashuSettings):
mint_private_key: str = Field(default=None)
mint_seed_decryption_key: Optional[str] = Field(default=None)
mint_derivation_path: str = Field(default="m/0'/0'/0'")
mint_derivation_path_list: List[str] = Field(default=[""])
mint_derivation_path_list: List[str] = Field(default=[])
mint_listen_host: str = Field(default="127.0.0.1")
mint_listen_port: int = Field(default=3338)

Expand Down Expand Up @@ -93,6 +93,7 @@ class MintLimits(MintSettings):
)
mint_max_request_length: int = Field(
default=1000,
gt=0,
title="Maximum request length",
description="Maximum length of REST API request arrays.",
)
Expand All @@ -104,16 +105,21 @@ class MintLimits(MintSettings):
)
mint_max_peg_in: int = Field(
default=None,
gt=0,
title="Maximum peg-in",
description="Maximum amount for a mint operation.",
)
mint_max_peg_out: int = Field(
default=None,
gt=0,
title="Maximum peg-out",
description="Maximum amount for a melt operation.",
)
mint_max_balance: int = Field(
default=None, title="Maximum mint balance", description="Maximum mint balance."
default=None,
gt=0,
title="Maximum mint balance",
description="Maximum mint balance.",
)


Expand Down Expand Up @@ -177,6 +183,7 @@ class LndRestFundingSource(MintSettings):
mint_lnd_rest_macaroon: Optional[str] = Field(default=None)
mint_lnd_rest_admin_macaroon: Optional[str] = Field(default=None)
mint_lnd_rest_invoice_macaroon: Optional[str] = Field(default=None)
mint_lnd_enable_mpp: bool = Field(default=False)


class CoreLightningRestFundingSource(MintSettings):
Expand Down
10 changes: 8 additions & 2 deletions cashu/lightning/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@

from pydantic import BaseModel

from ..core.base import Amount, MeltQuote, Unit
from ..core.base import (
Amount,
MeltQuote,
Unit,
)
from ..core.models import PostMeltQuoteRequest


class StatusResponse(BaseModel):
Expand Down Expand Up @@ -62,6 +67,7 @@ def __str__(self) -> str:


class LightningBackend(ABC):
supports_mpp: bool = False
supported_units: set[Unit]
unit: Unit

Expand Down Expand Up @@ -107,7 +113,7 @@ def get_payment_status(
@abstractmethod
async def get_payment_quote(
self,
bolt11: str,
melt_quote: PostMeltQuoteRequest,
) -> PaymentQuoteResponse:
pass

Expand Down
7 changes: 5 additions & 2 deletions cashu/lightning/blink.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
)
from loguru import logger

from ..core.base import Amount, MeltQuote, Unit
from ..core.base import Amount, MeltQuote, PostMeltQuoteRequest, Unit
from ..core.settings import settings
from .base import (
InvoiceResponse,
Expand Down Expand Up @@ -375,7 +375,10 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus:
preimage=preimage,
)

async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse:
async def get_payment_quote(
self, melt_quote: PostMeltQuoteRequest
) -> PaymentQuoteResponse:
bolt11 = melt_quote.request
variables = {
"input": {
"paymentRequest": bolt11,
Expand Down
8 changes: 5 additions & 3 deletions cashu/lightning/corelightningrest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
)
from loguru import logger

from ..core.base import Amount, MeltQuote, Unit
from ..core.base import Amount, MeltQuote, PostMeltQuoteRequest, Unit
from ..core.helpers import fee_reserve
from ..core.settings import settings
from .base import (
Expand Down Expand Up @@ -316,8 +316,10 @@ async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
)
await asyncio.sleep(0.02)

async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse:
invoice_obj = decode(bolt11)
async def get_payment_quote(
self, melt_quote: PostMeltQuoteRequest
) -> PaymentQuoteResponse:
invoice_obj = decode(melt_quote.request)
assert invoice_obj.amount_msat, "invoice has no amount."
amount_msat = int(invoice_obj.amount_msat)
fees_msat = fee_reserve(amount_msat)
Expand Down
8 changes: 5 additions & 3 deletions cashu/lightning/fake.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
encode,
)

from ..core.base import Amount, MeltQuote, Unit
from ..core.base import Amount, MeltQuote, PostMeltQuoteRequest, Unit
from ..core.helpers import fee_reserve
from ..core.settings import settings
from .base import (
Expand Down Expand Up @@ -152,8 +152,10 @@ async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
# amount = invoice_obj.amount_msat
# return InvoiceQuoteResponse(checking_id="", amount=amount)

async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse:
invoice_obj = decode(bolt11)
async def get_payment_quote(
self, melt_quote: PostMeltQuoteRequest
) -> PaymentQuoteResponse:
invoice_obj = decode(melt_quote.request)
assert invoice_obj.amount_msat, "invoice has no amount."

if self.unit == Unit.sat:
Expand Down
8 changes: 5 additions & 3 deletions cashu/lightning/lnbits.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
decode,
)

from ..core.base import Amount, MeltQuote, Unit
from ..core.base import Amount, MeltQuote, PostMeltQuoteRequest, Unit
from ..core.helpers import fee_reserve
from ..core.settings import settings
from .base import (
Expand Down Expand Up @@ -167,8 +167,10 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus:
preimage=data["preimage"],
)

async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse:
invoice_obj = decode(bolt11)
async def get_payment_quote(
self, melt_quote: PostMeltQuoteRequest
) -> PaymentQuoteResponse:
invoice_obj = decode(melt_quote.request)
assert invoice_obj.amount_msat, "invoice has no amount."
amount_msat = int(invoice_obj.amount_msat)
fees_msat = fee_reserve(amount_msat)
Expand Down
Loading

0 comments on commit a0614fe

Please sign in to comment.