From cb4bd7d7c10cadcb43f82c09b13ffed744e541f7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 17 May 2026 04:37:15 +0530 Subject: Phase 5: Lightning auto-payout with LNURL-pay and NUT-05 melt - New lnurl_pay.c/h: LNURL-pay protocol (GET .well-known/lnurlp + callback) - New lightning_payout.c/h: threshold-based auto-payout with multi-recipient split - Extended nucula_wallet bridge with nucula_wallet_melt() (NUT-05) - Config: payout section with multi-mint, multi-recipient, fee_tolerance - Default: enabled, TollGate@coinos.io, min_payout=128, min_balance=64 - 18 new unit tests (all passing), 134 total --- components/nucula_lib/nucula_wallet.cpp | 35 +++++++++++++++++++++++++++++++++ components/nucula_lib/nucula_wallet.h | 2 ++ 2 files changed, 37 insertions(+) (limited to 'components') diff --git a/components/nucula_lib/nucula_wallet.cpp b/components/nucula_lib/nucula_wallet.cpp index 50583f9..9a24e89 100644 --- a/components/nucula_lib/nucula_wallet.cpp +++ b/components/nucula_lib/nucula_wallet.cpp @@ -197,3 +197,38 @@ void nucula_wallet_print_status(void) proofs[i].amount, proofs[i].id.c_str()); } } + +esp_err_t nucula_wallet_melt(const char *bolt11_invoice, uint64_t max_fee_sats) +{ + if (!s_wallet || !bolt11_invoice) return ESP_FAIL; + + cashu::MeltQuote quote; + if (!s_wallet->request_melt_quote(std::string(bolt11_invoice), quote)) { + ESP_LOGE(TAG, "Melt quote request failed"); + return ESP_FAIL; + } + + uint64_t total_cost = (uint64_t)quote.amount + (uint64_t)quote.fee_reserve; + if (total_cost > max_fee_sats) { + ESP_LOGE(TAG, "Melt cost %llu exceeds max %llu (amount=%d fee=%d)", + (unsigned long long)total_cost, (unsigned long long)max_fee_sats, + quote.amount, quote.fee_reserve); + return ESP_FAIL; + } + + int balance_before = s_wallet->balance(); + if (balance_before < quote.amount) { + ESP_LOGE(TAG, "Insufficient balance: %d < %d", balance_before, quote.amount); + return ESP_FAIL; + } + + int change_amount = 0; + if (!s_wallet->melt_tokens(quote, change_amount)) { + ESP_LOGE(TAG, "Melt tokens failed"); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "Melted: %d sats paid, %d change, balance=%d->%d", + quote.amount, change_amount, balance_before, s_wallet->balance()); + return ESP_OK; +} diff --git a/components/nucula_lib/nucula_wallet.h b/components/nucula_lib/nucula_wallet.h index 64b7c24..784a126 100644 --- a/components/nucula_lib/nucula_wallet.h +++ b/components/nucula_lib/nucula_wallet.h @@ -22,6 +22,8 @@ char *nucula_wallet_proofs_json(void); esp_err_t nucula_wallet_swap_all(void); +esp_err_t nucula_wallet_melt(const char *bolt11_invoice, uint64_t max_fee_sats); + void nucula_wallet_print_status(void); #ifdef __cplusplus -- cgit v1.2.3