Skip to content

Commit

Permalink
remove LIGHTNING=True and pass quote id for melt
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Nov 7, 2023
1 parent 70f956c commit 3265a08
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 42 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@ To run the tests in this repository, first install the dev dependencies with
poetry install --with dev
```

Then, make sure to set up your `.env` file to use your local mint and disable Lightning and Tor:
Then, make sure to set up your mint's `.env` file to use a fake Lightning backend and disable Tor:
```bash
LIGHTNING=FALSE
MINT_LIGHTNING_BACKEND=FakeWallet
TOR=FALSE
```
You can run the tests with
Expand Down
2 changes: 1 addition & 1 deletion cashu/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ class PostMeltQuoteResponse(BaseModel):
quote: str # quote id
symbol: str # input symbol
amount: int # input amount
fee_reserve: Optional[int] = None # input fee reserve
fee_reserve: int # input fee reserve


# ------- API: MELT -------
Expand Down
2 changes: 2 additions & 0 deletions cashu/mint/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ async def get_melt_quote(
""",
(quote_id,),
)
if row is None:
return None
row_dict = dict(row)
return MintQuote(**row_dict) if row_dict else None

Expand Down
4 changes: 4 additions & 0 deletions cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ async def melt(
# TODO: needs logic to look up the lightning invoice from the quote ID
melt_quote = await self.crud.get_melt_quote(quote_id=quote, db=self.db)
assert melt_quote, "quote not found"
assert not melt_quote.issued, "quote already issued"
bolt11_request = melt_quote.request

logger.trace("melt called")
Expand Down Expand Up @@ -448,6 +449,9 @@ async def melt(
# melt successful, invalidate proofs
await self._invalidate_proofs(proofs)

# set quote as issued
await self.crud.update_melt_quote(quote_id=quote, issued=True, db=self.db)

# prepare change to compensate wallet for overpaid fees
return_promises: List[BlindedSignature] = []
if outputs and payment.fee_msat is not None:
Expand Down
18 changes: 9 additions & 9 deletions cashu/mint/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ async def mint_quote(payload: PostMintQuoteRequest) -> PostMintQuoteResponse:
Call `POST /mint` after paying the invoice.
"""
logger.trace(f"> POST /v1/mint: payload={payload}")
logger.trace(f"> POST /v1/mint/quote: payload={payload}")
amount = payload.amount
if amount > 21_000_000 * 100_000_000 or amount <= 0:
raise CashuError(code=0, detail="Amount must be a valid amount of sat.")
Expand All @@ -159,7 +159,7 @@ async def mint_quote(payload: PostMintQuoteRequest) -> PostMintQuoteResponse:
symbol="sat",
amount=amount,
)
logger.trace(f"< GET /mint: {resp}")
logger.trace(f"< POST /v1/mint/quote: {resp}")
return resp


Expand All @@ -178,13 +178,13 @@ async def mint(
"""
Requests the minting of tokens belonging to a paid payment request.
Call this endpoint after `GET /mint`.
Call this endpoint after `POST /v1/mint/quote`.
"""
logger.trace(f"> POST /mint: {payload}")
logger.trace(f"> POST /v1/mint: {payload}")

promises = await ledger.mint(outputs=payload.outputs, quote_id=payload.quote)
blinded_signatures = PostMintResponse(quote=payload.quote, signatures=promises)
logger.trace(f"< POST /mint: {blinded_signatures}")
logger.trace(f"< POST /v1/mint: {blinded_signatures}")
return blinded_signatures


Expand All @@ -198,9 +198,9 @@ async def melt_quote(payload: PostMeltQuoteRequest) -> PostMeltQuoteResponse:
"""
Request a quote for melting tokens.
"""
logger.trace(f"> POST /melt/quote: {payload}")
logger.trace(f"> POST /v1/melt/quote: {payload}")
quote = await ledger.melt_quote(payload) # TODO
logger.trace(f"< POST /melt/quote: {quote}")
logger.trace(f"< POST /v1/melt/quote: {quote}")
return quote


Expand All @@ -221,14 +221,14 @@ async def melt(payload: PostMeltRequest) -> PostMeltResponse:
"""
Requests tokens to be destroyed and sent out via Lightning.
"""
logger.trace(f"> POST /melt: {payload}")
logger.trace(f"> POST /v1/melt: {payload}")
ok, preimage, change_promises = await ledger.melt(
payload.inputs, payload.quote, payload.outputs
)
resp = PostMeltResponse(
quote="to_be_replaced", paid=ok, proof=preimage, change=change_promises
)
logger.trace(f"< POST /melt: {resp}")
logger.trace(f"< POST /v1/melt: {resp}")
return resp


Expand Down
8 changes: 3 additions & 5 deletions cashu/wallet/api/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,15 @@ async def swap(

# pay invoice from outgoing mint
await outgoing_wallet.load_proofs(reload=True)
total_amount, fee_reserve_sat = await outgoing_wallet.get_pay_amount_with_fees(
invoice.bolt11
)
assert total_amount > 0, "amount must be positive"
quote = await outgoing_wallet.get_pay_amount_with_fees(invoice.bolt11)
total_amount = quote.amount + quote.fee_reserve
if outgoing_wallet.available_balance < total_amount:
raise Exception("balance too low")

_, send_proofs = await outgoing_wallet.split_to_send(
outgoing_wallet.proofs, total_amount, set_reserved=True
)
await outgoing_wallet.pay_lightning(send_proofs, invoice.bolt11, fee_reserve_sat)
await outgoing_wallet.pay_lightning(send_proofs, invoice.bolt11, quote.fee_reserve, quote.quote)

# mint token in incoming mint
await incoming_wallet.mint(amount, id=invoice.id)
Expand Down
16 changes: 8 additions & 8 deletions cashu/wallet/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,13 @@ async def pay(ctx: Context, invoice: str, yes: bool):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_mint()
wallet.status()
total_amount, fee_reserve_sat = await wallet.get_pay_amount_with_fees(invoice)
quote = await wallet.get_pay_amount_with_fees(invoice)
total_amount = quote.amount + quote.fee_reserve
if not yes:
potential = (
f" ({total_amount} sat with potential fees)" if fee_reserve_sat else ""
f" ({total_amount} sat with potential fees)" if quote.fee_reserve else ""
)
message = f"Pay {total_amount - fee_reserve_sat} sat{potential}?"
message = f"Pay {quote.amount} sat{potential}?"
click.confirm(
message,
abort=True,
Expand All @@ -184,7 +185,7 @@ async def pay(ctx: Context, invoice: str, yes: bool):
print("Error: Balance too low.")
return
_, send_proofs = await wallet.split_to_send(wallet.proofs, total_amount)
await wallet.pay_lightning(send_proofs, invoice, fee_reserve_sat)
await wallet.pay_lightning(send_proofs, invoice, quote.fee_reserve, quote.quote)
wallet.status()


Expand Down Expand Up @@ -283,15 +284,14 @@ async def swap(ctx: Context):
invoice = await incoming_wallet.request_mint(amount)

# pay invoice from outgoing mint
total_amount, fee_reserve_sat = await outgoing_wallet.get_pay_amount_with_fees(
invoice.bolt11
)
quote = await outgoing_wallet.get_pay_amount_with_fees(invoice.bolt11)
total_amount = quote.amount + quote.fee_reserve
if outgoing_wallet.available_balance < total_amount:
raise Exception("balance too low")
_, send_proofs = await outgoing_wallet.split_to_send(
outgoing_wallet.proofs, total_amount, set_reserved=True
)
await outgoing_wallet.pay_lightning(send_proofs, invoice.bolt11, fee_reserve_sat)
await outgoing_wallet.pay_lightning(send_proofs, invoice.bolt11, quote.fee_reserve, quote.quote)

# mint token in incoming mint
await incoming_wallet.mint(amount, id=invoice.id)
Expand Down
33 changes: 17 additions & 16 deletions cashu/wallet/wallet.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import base64
import json
import math
import time
import uuid
from itertools import groupby
Expand Down Expand Up @@ -33,6 +32,7 @@
PostMintResponse,
PostRestoreResponse,
PostSplitRequest,
PostSplitResponse,
Proof,
TokenV2,
TokenV2Mint,
Expand Down Expand Up @@ -405,7 +405,7 @@ async def mint_quote(self, amount) -> Invoice:
logger.trace("Requesting mint: GET /v1/mint")
payload = PostMintQuoteRequest(method="bolt11", symbol="sat", amount=amount)
resp = await self.httpx.post(
join(self.url, "/v1/mint/quote"), json=payload.json()
join(self.url, "/v1/mint/quote"), json=payload.dict()
)
# BEGIN backwards compatibility < 0.14.0
# assume the mint has not upgraded yet if we get a 404
Expand Down Expand Up @@ -488,9 +488,7 @@ async def melt(
Accepts proofs and a lightning invoice to pay in exchange.
"""

payload = PostMeltRequest(
quote="to_be_replaced", inputs=proofs, outputs=outputs
)
payload = PostMeltRequest(quote=quote, inputs=proofs, outputs=outputs)

def _meltrequest_include_fields(proofs: List[Proof]):
"""strips away fields from the model that aren't necessary for the /melt"""
Expand Down Expand Up @@ -533,7 +531,7 @@ def _splitrequest_include_fields(proofs: List[Proof]):
}
return {
"outputs": ...,
"proofs": {i: proofs_include for i in range(len(proofs))},
"inputs": {i: proofs_include for i in range(len(proofs))},
}

resp = await self.httpx.post(
Expand All @@ -542,7 +540,8 @@ def _splitrequest_include_fields(proofs: List[Proof]):
)
self.raise_on_error_request(resp)
promises_dict = resp.json()
mint_response = PostMintResponse.parse_obj(promises_dict)
print(promises_dict)
mint_response = PostSplitResponse.parse_obj(promises_dict)
promises = [BlindedSignature(**p.dict()) for p in mint_response.signatures]

if len(promises) == 0:
Expand Down Expand Up @@ -691,7 +690,7 @@ async def mint(
Args:
amount (int): Total amount of tokens to be minted
id (str): Id for looking up the paid Lightning invoice. Defaults to None (for testing with LIGHTNING=False).
id (str): Id for looking up the paid Lightning invoice.
split (Optional[List[str]], optional): List of desired amount splits to be minted. Total must sum to `amount`.
Raises:
Expand Down Expand Up @@ -843,7 +842,7 @@ async def split(
return keep_proofs, send_proofs

async def pay_lightning(
self, proofs: List[Proof], invoice: str, fee_reserve_sat: int
self, proofs: List[Proof], invoice: str, fee_reserve_sat: int, quote_id: str
) -> PostMeltResponse:
"""Pays a lightning invoice and returns the status of the payment.
Expand Down Expand Up @@ -889,7 +888,7 @@ async def pay_lightning(
# store invoice in db as not paid yet
await store_lightning_invoice(db=self.db, invoice=invoice_obj)

status = await super().melt("to_be_replaced", proofs, change_outputs)
status = await super().melt(quote_id, proofs, change_outputs)

# if payment fails
if not status.paid:
Expand Down Expand Up @@ -1323,14 +1322,16 @@ async def get_pay_amount_with_fees(self, invoice: str):
Decodes the amount from a Lightning invoice and returns the
total amount (amount+fees) to be paid.
"""
decoded_invoice = bolt11.decode(invoice)
assert decoded_invoice.amount_msat, "invoices has no amount."
# decoded_invoice = bolt11.decode(invoice)
# assert decoded_invoice.amount_msat, "invoices has no amount."
# check if it's an internal payment
melt_quote = await self.melt_quote(invoice)
fees = melt_quote.fee_reserve or 0
logger.debug(f"Mint wants {fees} sat as fee reserve.")
amount = math.ceil((decoded_invoice.amount_msat + fees * 1000) / 1000) # 1% fee
return amount, fees
# fees = melt_quote.fee_reserve or 0
logger.debug(
f"Mint wants {melt_quote.fee_reserve} {melt_quote.symbol} as fee reserve."
)
# amount = math.ceil((decoded_invoice.amount_msat + fees * 1000) / 1000) # 1% fee
return melt_quote

async def split_to_send(
self,
Expand Down
4 changes: 3 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
settings.mint_host = "0.0.0.0"
settings.mint_listen_port = SERVER_PORT
settings.mint_url = SERVER_ENDPOINT
settings.lightning = True
settings.tor = False
settings.mint_lightning_backend = "FakeWallet"
settings.fakewallet_brr = True
settings.fakewallet_delay_payment = False
settings.fakewallet_stochastic_invoice = False
settings.mint_database = "./test_data/test_mint"
settings.mint_derivation_path = "0/0/0/0"
settings.mint_private_key = "TEST_PRIVATE_KEY"
Expand Down

0 comments on commit 3265a08

Please sign in to comment.