From 2189728771e318f6e8431303bc3c7af45ce2db11 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 19 Feb 2024 16:30:44 +0100 Subject: [PATCH] blink: round up fees to next satoshi (#445) --- cashu/lightning/blink.py | 14 ++++++++--- tests/test_mint_lightning_blink.py | 39 +++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/cashu/lightning/blink.py b/cashu/lightning/blink.py index eb78ed29..83348d5f 100644 --- a/cashu/lightning/blink.py +++ b/cashu/lightning/blink.py @@ -393,10 +393,18 @@ async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse: amount_msat = int(invoice_obj.amount_msat) - # we take the highest: fee_msat_response, or BLINK_MAX_FEE_PERCENT, or 2000 msat - fees_msat = max( + # we take the highest: fee_msat_response, or BLINK_MAX_FEE_PERCENT, or MINIMUM_FEE_MSAT msat + # Note: fees with BLINK_MAX_FEE_PERCENT are rounded to the nearest 1000 msat + fees_amount_msat: int = ( + math.ceil(amount_msat / 100 * BLINK_MAX_FEE_PERCENT / 1000) * 1000 + ) + + fees_msat: int = max( fees_response_msat, - max(math.ceil(amount_msat / 100 * BLINK_MAX_FEE_PERCENT), MINIMUM_FEE_MSAT), + max( + fees_amount_msat, + MINIMUM_FEE_MSAT, + ), ) fees = Amount(unit=Unit.msat, amount=fees_msat) diff --git a/tests/test_mint_lightning_blink.py b/tests/test_mint_lightning_blink.py index 393829ad..64777d6e 100644 --- a/tests/test_mint_lightning_blink.py +++ b/tests/test_mint_lightning_blink.py @@ -4,7 +4,7 @@ from cashu.core.base import Amount, MeltQuote, Unit from cashu.core.settings import settings -from cashu.lightning.blink import BlinkWallet +from cashu.lightning.blink import MINIMUM_FEE_MSAT, BlinkWallet settings.mint_blink_key = "123" blink = BlinkWallet() @@ -12,6 +12,23 @@ "lnbc10u1pjap7phpp50s9lzr3477j0tvacpfy2ucrs4q0q6cvn232ex7nt2zqxxxj8gxrsdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzzsxqrrsss" "p575z0n39w2j7zgnpqtdlrgz9rycner4eptjm3lz363dzylnrm3h4s9qyyssqfz8jglcshnlcf0zkw4qu8fyr564lg59x5al724kms3h6gpuhx9xrfv27tgx3l3u3cyf6" "3r52u0xmac6max8mdupghfzh84t4hfsvrfsqwnuszf" +) # 1000 sat + +payment_request_10k = ( + "lnbc100u1pjaxuyzpp5wn37d3mx38haqs7nd5he4j7pq4r806e6s83jdksxrd77pnanm3zqdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzzsxqrrss" + "sp5ayy0uuhwgy8hwphvy7ptzpg2dfn8vt3vlgsk53rsvj76jvafhujs9qyyssqc8aj03s5au3tgu6pj0rm0ws4a838s8ffe3y3qkj77esh7qmgsz7qlvdlzgj6dvx7tx7" + "zn6k352z85rvdqvlszrevvzakp96a4pvyn2cpgaaks6" +) + +payment_request_4973 = ( + "lnbc49730n1pjaxuxnpp5zw0ry2w2heyuv7wk4r6z38vvgnaudfst0hl2p5xnv0mjkxtavg2qdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzzsxqrr" + "sssp5x8tv2ka0m95hgek25kauw540m0dx727stqqr07l8h37v5283sn5q9qyyssqeevcs6vxcdnerk5w5mwfmntsf8nze7nxrf97dywmga7v0742vhmxtjrulgu3kah4f" + "2r6025j974jpjg4mkqhv2gdls5k7e5cvwdf4wcp3ytsvx" +) +payment_request_1 = ( + "lnbc10n1pjaxujrpp5sqehn6h5p8xpa0c0lvj5vy3a537gxfk5e7h2ate2alfw3y5cm6xqdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzzsxqrrsss" + "p5fkxsvyl0r32mvnhv9cws4rp986v0wjl2lp93zzl8jejnuwzvpynq9qyyssqqmsnatsz87qrgls98c97dfa6l2z3rzg2x6kxmrvpz886rwjylmd56y3qxzfulrq03kkh" + "hwk6r32wes6pjt2zykhnsjn30c6uhuk0wugp3x74al" ) @@ -132,7 +149,7 @@ async def test_blink_get_payment_status(): @respx.mock @pytest.mark.asyncio async def test_blink_get_payment_quote(): - # response says 1 sat fees but invoice * 0.5% is 5 sat so we expect 5 sat + # response says 1 sat fees but invoice (1000 sat) * 0.5% is 5 sat so we expect 5 sat mock_response = {"data": {"lnInvoiceFeeProbe": {"amount": 1}}} respx.post(blink.endpoint).mock(return_value=Response(200, json=mock_response)) quote = await blink.get_payment_quote(payment_request) @@ -140,10 +157,26 @@ async def test_blink_get_payment_quote(): assert quote.amount == Amount(Unit.msat, 1000000) # msat assert quote.fee == Amount(Unit.msat, 5000) # msat - # response says 10 sat fees but invoice * 0.5% is 5 sat so we expect 10 sat + # response says 10 sat fees but invoice (1000 sat) * 0.5% is 5 sat so we expect 10 sat mock_response = {"data": {"lnInvoiceFeeProbe": {"amount": 10}}} respx.post(blink.endpoint).mock(return_value=Response(200, json=mock_response)) quote = await blink.get_payment_quote(payment_request) assert quote.checking_id == payment_request assert quote.amount == Amount(Unit.msat, 1000000) # msat assert quote.fee == Amount(Unit.msat, 10000) # msat + + # response says 10 sat fees but invoice (4973 sat) * 0.5% is 24.865 sat so we expect 25 sat + mock_response = {"data": {"lnInvoiceFeeProbe": {"amount": 10}}} + respx.post(blink.endpoint).mock(return_value=Response(200, json=mock_response)) + quote = await blink.get_payment_quote(payment_request_4973) + assert quote.checking_id == payment_request_4973 + assert quote.amount == Amount(Unit.msat, 4973000) # msat + assert quote.fee == Amount(Unit.msat, 25000) # msat + + # response says 0 sat fees but invoice (1 sat) * 0.5% is 0.005 sat so we expect MINIMUM_FEE_MSAT/1000 sat + mock_response = {"data": {"lnInvoiceFeeProbe": {"amount": 0}}} + respx.post(blink.endpoint).mock(return_value=Response(200, json=mock_response)) + quote = await blink.get_payment_quote(payment_request_1) + assert quote.checking_id == payment_request_1 + assert quote.amount == Amount(Unit.msat, 1000) # msat + assert quote.fee == Amount(Unit.msat, MINIMUM_FEE_MSAT) # msat