mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 11:04:19 +01:00
Mint: settle mint-melt on same mint with different units externally (#651)
* WIP settle different units externally * mint melt externally different units * deprecated route return only sat * comment --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
@@ -30,6 +30,7 @@ from .base import (
|
||||
|
||||
|
||||
class FakeWallet(LightningBackend):
|
||||
unit: Unit
|
||||
fake_btc_price = 1e8 / 1337
|
||||
paid_invoices_queue: asyncio.Queue[Bolt11] = asyncio.Queue(0)
|
||||
payment_secrets: Dict[str, str] = dict()
|
||||
@@ -46,7 +47,6 @@ class FakeWallet(LightningBackend):
|
||||
).hex()
|
||||
|
||||
supported_units = {Unit.sat, Unit.msat, Unit.usd, Unit.eur}
|
||||
unit = Unit.sat
|
||||
|
||||
supports_incoming_payment_stream: bool = True
|
||||
supports_description: bool = True
|
||||
|
||||
@@ -660,7 +660,7 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
# so that we would be able to handle the transaction internally
|
||||
# and therefore respond with internal transaction fees (0 for now)
|
||||
mint_quote = await self.crud.get_mint_quote(request=request, db=self.db)
|
||||
if mint_quote:
|
||||
if mint_quote and mint_quote.unit == melt_quote.unit:
|
||||
payment_quote = self.create_internal_melt_quote(mint_quote, melt_quote)
|
||||
else:
|
||||
# not internal
|
||||
@@ -811,6 +811,10 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
if not mint_quote:
|
||||
return melt_quote
|
||||
|
||||
# settle externally if units are different
|
||||
if mint_quote.unit != melt_quote.unit:
|
||||
return melt_quote
|
||||
|
||||
# we settle the transaction internally
|
||||
if melt_quote.paid:
|
||||
raise TransactionError("melt quote already paid")
|
||||
@@ -825,8 +829,6 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
raise TransactionError("amounts do not match")
|
||||
if not bolt11_request == mint_quote.request:
|
||||
raise TransactionError("bolt11 requests do not match")
|
||||
if not mint_quote.unit == melt_quote.unit:
|
||||
raise TransactionError("units do not match")
|
||||
if not mint_quote.method == melt_quote.method:
|
||||
raise TransactionError("methods do not match")
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import Dict, List, Optional
|
||||
from fastapi import APIRouter, Request
|
||||
from loguru import logger
|
||||
|
||||
from ..core.base import BlindedMessage, BlindedSignature
|
||||
from ..core.base import BlindedMessage, BlindedSignature, Unit
|
||||
from ..core.errors import CashuError
|
||||
from ..core.models import (
|
||||
CheckFeesRequest_deprecated,
|
||||
@@ -114,7 +114,8 @@ async def keyset_deprecated(idBase64Urlsafe: str) -> Dict[str, str]:
|
||||
async def keysets_deprecated() -> KeysetsResponse_deprecated:
|
||||
"""This endpoint returns a list of keysets that the mint currently supports and will accept tokens from."""
|
||||
logger.trace("> GET /keysets")
|
||||
keysets = KeysetsResponse_deprecated(keysets=list(ledger.keysets.keys()))
|
||||
sat_keysets = {k: v for k, v in ledger.keysets.items() if v.unit == Unit.sat}
|
||||
keysets = KeysetsResponse_deprecated(keysets=list(sat_keysets.keys()))
|
||||
return keysets
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ settings.mint_url = SERVER_ENDPOINT
|
||||
settings.tor = False
|
||||
settings.wallet_unit = "sat"
|
||||
settings.mint_backend_bolt11_sat = settings.mint_backend_bolt11_sat or "FakeWallet"
|
||||
settings.mint_backend_bolt11_usd = settings.mint_backend_bolt11_usd or "FakeWallet"
|
||||
settings.fakewallet_brr = True
|
||||
settings.fakewallet_delay_outgoing_payment = 0
|
||||
settings.fakewallet_delay_incoming_payment = 1
|
||||
@@ -42,7 +43,7 @@ assert (
|
||||
), "Test database is the same as the main database"
|
||||
settings.mint_database = settings.mint_test_database
|
||||
settings.mint_derivation_path = "m/0'/0'/0'"
|
||||
settings.mint_derivation_path_list = []
|
||||
settings.mint_derivation_path_list = ["m/0'/2'/0'"] # USD
|
||||
settings.mint_private_key = "TEST_PRIVATE_KEY"
|
||||
settings.mint_seed_decryption_key = ""
|
||||
settings.mint_max_balance = 0
|
||||
@@ -85,13 +86,6 @@ class UvicornServer(multiprocessing.Process):
|
||||
async def ledger():
|
||||
async def start_mint_init(ledger: Ledger) -> Ledger:
|
||||
await migrate_databases(ledger.db, migrations_mint)
|
||||
ledger = Ledger(
|
||||
db=Database("mint", settings.mint_database),
|
||||
seed=settings.mint_private_key,
|
||||
derivation_path=settings.mint_derivation_path,
|
||||
backends=backends,
|
||||
crud=LedgerCrudSqlite(),
|
||||
)
|
||||
await ledger.startup_ledger()
|
||||
return ledger
|
||||
|
||||
@@ -110,9 +104,17 @@ async def ledger():
|
||||
await db.engine.dispose()
|
||||
|
||||
wallets_module = importlib.import_module("cashu.lightning")
|
||||
lightning_backend = getattr(wallets_module, settings.mint_backend_bolt11_sat)()
|
||||
lightning_backend_sat = getattr(wallets_module, settings.mint_backend_bolt11_sat)(
|
||||
unit=Unit.sat
|
||||
)
|
||||
lightning_backend_usd = getattr(wallets_module, settings.mint_backend_bolt11_usd)(
|
||||
unit=Unit.usd
|
||||
)
|
||||
backends = {
|
||||
Method.bolt11: {Unit.sat: lightning_backend},
|
||||
Method.bolt11: {
|
||||
Unit.sat: lightning_backend_sat,
|
||||
Unit.usd: lightning_backend_usd,
|
||||
},
|
||||
}
|
||||
ledger = Ledger(
|
||||
db=Database("mint", settings.mint_database),
|
||||
|
||||
@@ -94,6 +94,12 @@ async def test_api_keysets(ledger: Ledger):
|
||||
"active": True,
|
||||
"input_fee_ppk": 0,
|
||||
},
|
||||
{
|
||||
"id": "00c074b96c7e2b0e",
|
||||
"unit": "usd",
|
||||
"active": True,
|
||||
"input_fee_ppk": 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
assert response.json() == expected
|
||||
|
||||
@@ -2,7 +2,7 @@ import httpx
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from cashu.core.base import Proof
|
||||
from cashu.core.base import Proof, Unit
|
||||
from cashu.core.models import (
|
||||
CheckSpendableRequest_deprecated,
|
||||
CheckSpendableResponse_deprecated,
|
||||
@@ -51,7 +51,8 @@ async def test_api_keysets(ledger: Ledger):
|
||||
response = httpx.get(f"{BASE_URL}/keysets")
|
||||
assert response.status_code == 200, f"{response.url} {response.status_code}"
|
||||
assert ledger.keyset.public_keys
|
||||
assert response.json()["keysets"] == list(ledger.keysets.keys())
|
||||
sat_keysets = {k: v for k, v in ledger.keysets.items() if v.unit == Unit.sat}
|
||||
assert response.json()["keysets"] == list(sat_keysets.keys())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -60,7 +60,7 @@ async def wallet(ledger: Ledger):
|
||||
async def test_init_keysets(ledger: Ledger):
|
||||
ledger.keysets = {}
|
||||
await ledger.init_keysets()
|
||||
assert len(ledger.keysets) == 1
|
||||
assert len(ledger.keysets) == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -5,7 +5,7 @@ import pytest_asyncio
|
||||
|
||||
from cashu.core.base import MeltQuote, MeltQuoteState, Proof
|
||||
from cashu.core.errors import LightningError
|
||||
from cashu.core.models import PostMeltQuoteRequest
|
||||
from cashu.core.models import PostMeltQuoteRequest, PostMintQuoteRequest
|
||||
from cashu.core.settings import settings
|
||||
from cashu.lightning.base import PaymentResult
|
||||
from cashu.mint.ledger import Ledger
|
||||
@@ -331,3 +331,40 @@ async def test_melt_lightning_pay_invoice_exception_exception(
|
||||
ledger.melt(proofs=wallet.proofs, quote=quote_id),
|
||||
"Melt is disabled. Please contact the operator.",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(is_regtest, reason="only fake wallet")
|
||||
async def test_mint_melt_different_units(ledger: Ledger, wallet: Wallet):
|
||||
"""Mint and melt different units."""
|
||||
# load the wallet
|
||||
invoice = await wallet.request_mint(64)
|
||||
await wallet.mint(64, id=invoice.id)
|
||||
|
||||
amount = 32
|
||||
|
||||
# mint quote in sat
|
||||
sat_mint_quote = await ledger.mint_quote(
|
||||
quote_request=PostMintQuoteRequest(amount=amount, unit="sat")
|
||||
)
|
||||
sat_invoice = sat_mint_quote.request
|
||||
assert sat_mint_quote.paid is False
|
||||
|
||||
# melt quote in usd
|
||||
usd_melt_quote = await ledger.melt_quote(
|
||||
PostMeltQuoteRequest(unit="usd", request=sat_invoice)
|
||||
)
|
||||
assert usd_melt_quote.paid is False
|
||||
|
||||
# pay melt quote with usd
|
||||
await ledger.melt(proofs=wallet.proofs, quote=usd_melt_quote.quote)
|
||||
|
||||
output_amounts = [32]
|
||||
|
||||
secrets, rs, derivation_paths = await wallet.generate_n_secrets(len(output_amounts))
|
||||
outputs, rs = wallet._construct_outputs(output_amounts, secrets, rs)
|
||||
|
||||
# mint in sat
|
||||
mint_resp = await ledger.mint(outputs=outputs, quote_id=sat_mint_quote.quote)
|
||||
|
||||
assert len(mint_resp) == len(outputs)
|
||||
|
||||
Reference in New Issue
Block a user