Skip to content

Commit 5065446

Browse files
committed
feat: lightning backend interface
1 parent 3c82013 commit 5065446

File tree

8 files changed

+156
-15
lines changed

8 files changed

+156
-15
lines changed

src/core/lightning/lightning.zig

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
const root = @import("../../lib.zig");
33
const std = @import("std");
44

5+
pub const MintLightning = @import("mint.zig");
6+
57
const Bolt11Invoice = root.lightning_invoices.Bolt11Invoice;
68
const Amount = root.core.amount.Amount;
79
const MeltQuoteState = root.core.nuts.nut05.QuoteState;

src/core/lightning/mint.zig

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/// MintLightning interface for backend
2+
const Self = @This();
3+
4+
const std = @import("std");
5+
const core = @import("../lib.zig");
6+
7+
const Channel = @import("../../channels/channels.zig").Channel;
8+
const Amount = core.amount.Amount;
9+
const PaymentQuoteResponse = core.lightning.PaymentQuoteResponse;
10+
const CreateInvoiceResponse = core.lightning.CreateInvoiceResponse;
11+
const PayInvoiceResponse = core.lightning.PayInvoiceResponse;
12+
const MeltQuoteBolt11Request = core.nuts.nut05.MeltQuoteBolt11Request;
13+
const Settings = core.lightning.Settings;
14+
const MintMeltSettings = core.lightning.MintMeltSettings;
15+
const FeeReserve = core.mint.FeeReserve;
16+
const MintQuoteState = core.nuts.nut04.QuoteState;
17+
18+
// _type: type,
19+
allocator: std.mem.Allocator,
20+
ptr: *anyopaque,
21+
22+
deinitFn: *const fn (ptr: *anyopaque) void,
23+
getSettingsFn: *const fn (ptr: *anyopaque) Settings,
24+
waitAnyInvoiceFn: *const fn (ptr: *anyopaque) anyerror!Channel(std.ArrayList(u8)).Rx,
25+
getPaymentQuoteFn: *const fn (ptr: *anyopaque, alloc: std.mem.Allocator, melt_quote_request: MeltQuoteBolt11Request) anyerror!PaymentQuoteResponse,
26+
payInvoiceFn: *const fn (ptr: *anyopaque, alloc: std.mem.Allocator, melt_quote: core.mint.MeltQuote, partial_msats: ?Amount, max_fee_msats: ?Amount) anyerror!PayInvoiceResponse,
27+
checkInvoiceStatusFn: *const fn (ptr: *anyopaque, request_lookup_id: []const u8) anyerror!MintQuoteState,
28+
createInvoiceFn: *const fn (ptr: *anyopaque, gpa: std.mem.Allocator, amount: Amount, unit: core.nuts.CurrencyUnit, description: []const u8, unix_expiry: u64) anyerror!CreateInvoiceResponse,
29+
30+
pub fn initFrom(comptime T: type, allocator: std.mem.Allocator, value: T) !Self {
31+
const gen = struct {
32+
pub fn getSettings(pointer: *anyopaque) Settings {
33+
const self: *T = @ptrCast(@alignCast(pointer));
34+
return self.getSettings();
35+
}
36+
37+
pub fn waitAnyInvoice(pointer: *anyopaque) anyerror!Channel(std.ArrayList(u8)).Rx {
38+
const self: *T = @ptrCast(@alignCast(pointer));
39+
return self.waitAnyInvoice();
40+
}
41+
42+
pub fn getPaymentQuote(pointer: *anyopaque, arena: std.mem.Allocator, melt_quote_request: MeltQuoteBolt11Request) anyerror!PaymentQuoteResponse {
43+
const self: *T = @ptrCast(@alignCast(pointer));
44+
return self.getPaymentQuote(arena, melt_quote_request);
45+
}
46+
47+
pub fn payInvoice(pointer: *anyopaque, arena: std.mem.Allocator, melt_quote: core.mint.MeltQuote, partial_msats: ?Amount, max_fee_msats: ?Amount) !PayInvoiceResponse {
48+
const self: *T = @ptrCast(@alignCast(pointer));
49+
return self.payInvoice(arena, melt_quote, partial_msats, max_fee_msats);
50+
}
51+
52+
pub fn checkInvoiceStatus(pointer: *anyopaque, request_lookup_id: []const u8) !MintQuoteState {
53+
const self: *T = @ptrCast(@alignCast(pointer));
54+
return self.checkInvoiceStatus(request_lookup_id);
55+
}
56+
57+
pub fn createInvoice(pointer: *anyopaque, arena: std.mem.Allocator, amount: Amount, unit: core.nuts.CurrencyUnit, description: []const u8, unix_expiry: u64) !CreateInvoiceResponse {
58+
const self: *T = @ptrCast(@alignCast(pointer));
59+
return self.createInvoice(arena, amount, unit, description, unix_expiry);
60+
}
61+
62+
pub fn deinit(pointer: *anyopaque) void {
63+
if (std.meta.hasFn(T, "deinit")) {
64+
const self: *T = @ptrCast(@alignCast(pointer));
65+
self.deinit();
66+
}
67+
}
68+
};
69+
70+
const ptr = try allocator.create(T);
71+
ptr.* = value;
72+
73+
return .{
74+
// ._type = T,
75+
.allocator = allocator,
76+
.ptr = ptr,
77+
.getSettingsFn = gen.getSettings,
78+
.waitAnyInvoiceFn = gen.waitAnyInvoice,
79+
.getPaymentQuoteFn = gen.getPaymentQuote,
80+
.payInvoiceFn = gen.payInvoice,
81+
.checkInvoiceStatusFn = gen.checkInvoiceStatus,
82+
.createInvoiceFn = gen.createInvoice,
83+
.deinitFn = gen.deinit,
84+
};
85+
}
86+
87+
pub fn deinit(self: Self) void {
88+
self.deinitFn(self.ptr);
89+
// clearing pointer
90+
// self.allocator.destroy(@as(self._type, @ptrCast(self.ptr)));
91+
}
92+
93+
pub fn getSettings(self: Self) Settings {
94+
return self.getSettingsFn(self.ptr);
95+
}
96+
97+
pub fn waitAnyInvoice(self: Self) !Channel(std.ArrayList(u8)).Rx {
98+
return self.waitAnyInvoiceFn(self.ptr);
99+
}
100+
101+
pub fn getPaymentQuote(self: Self, arena: std.mem.Allocator, melt_quote_request: MeltQuoteBolt11Request) !PaymentQuoteResponse {
102+
return self.getPaymentQuoteFn(self.ptr, arena, melt_quote_request);
103+
}
104+
105+
pub fn payInvoice(self: Self, arena: std.mem.Allocator, melt_quote: core.mint.MeltQuote, partial_msats: ?Amount, max_fee_msats: ?Amount) !PayInvoiceResponse {
106+
return self.payInvoiceFn(self.ptr, arena, melt_quote, partial_msats, max_fee_msats);
107+
}
108+
109+
pub fn checkInvoiceStatus(self: Self, request_lookup_id: []const u8) !MintQuoteState {
110+
return self.checkInvoiceStatusFn(self.ptr, request_lookup_id);
111+
}
112+
113+
pub fn createInvoice(self: Self, arena: std.mem.Allocator, amount: Amount, unit: core.nuts.CurrencyUnit, description: []const u8, unix_expiry: u64) !CreateInvoiceResponse {
114+
return self.createInvoiceFn(self.ptr, arena, amount, unit, description, unix_expiry);
115+
}

src/core/mint/types.zig

+10
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ pub const MeltQuote = struct {
109109
/// Value used by ln backend to look up state of request
110110
request_lookup_id: []const u8,
111111

112+
/// formatting mint quote
113+
pub fn format(
114+
self: MeltQuote,
115+
comptime _: []const u8,
116+
_: std.fmt.FormatOptions,
117+
writer: anytype,
118+
) !void {
119+
try writer.print("{}", .{std.json.fmt(self, .{})});
120+
}
121+
112122
/// Create new [`MeltQuote`]
113123
pub fn init(
114124
request: []const u8,

src/fake_wallet/fake_wallet.zig

+17-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const MintMeltSettings = core.lightning.MintMeltSettings;
1818
const FeeReserve = core.mint.FeeReserve;
1919
const Channel = @import("../channels/channels.zig").Channel;
2020
const MintQuoteState = core.nuts.nut04.QuoteState;
21+
const MintLightning = core.lightning.MintLightning;
2122

2223
// TODO: wait any invoices, here we need create a new listener, that will receive
2324
// message like pub sub channel
@@ -68,6 +69,10 @@ pub const FakeWallet = struct {
6869
};
6970
}
7071

72+
pub fn toMintLightning(self: *const Self, gpa: std.mem.Allocator) error{OutOfMemory}!MintLightning {
73+
return MintLightning.initFrom(Self, gpa, self.*);
74+
}
75+
7176
pub fn deinit(self: *FakeWallet) void {
7277
self.chan.deinit();
7378
self.thread_pool.deinit(self.allocator);
@@ -229,4 +234,15 @@ pub const FakeWallet = struct {
229234
}
230235
};
231236

232-
test {}
237+
test {
238+
var mint = try FakeWallet.init(std.testing.allocator, .{}, .{}, .{});
239+
defer mint.deinit();
240+
241+
const ln = mint.toMintLightning();
242+
const settings = try ln.getSettings();
243+
244+
const _settings = mint.getSettings();
245+
246+
std.testing.expectEqual(settings, _settings);
247+
std.log.warn("qq", .{});
248+
}

src/fake_wallet/pub_sub.zig

-1
This file was deleted.

src/mint.zig

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const builtin = @import("builtin");
99
const config = @import("mintd/config.zig");
1010
const clap = @import("clap");
1111

12+
const MintLightning = core.lightning.MintLightning;
1213
const MintState = @import("router/router.zig").MintState;
1314
const LnKey = @import("router/router.zig").LnKey;
1415
const FakeWallet = @import("fake_wallet/fake_wallet.zig").FakeWallet;
@@ -135,6 +136,7 @@ pub fn main() !void {
135136
var ln_backends = router.LnBackendsMap.init(gpa.allocator());
136137
defer {
137138
var it = ln_backends.valueIterator();
139+
138140
while (it.next()) |v| {
139141
v.deinit();
140142
}
@@ -153,7 +155,10 @@ pub fn main() !void {
153155
var wallet = try FakeWallet.init(gpa.allocator(), fee_reserve, .{}, .{});
154156
errdefer wallet.deinit();
155157

156-
try ln_backends.put(ln_key, wallet);
158+
const ln_mint = try wallet.toMintLightning(gpa.allocator());
159+
errdefer ln_mint.deinit();
160+
161+
try ln_backends.put(ln_key, ln_mint);
157162

158163
try supported_units.put(unit, .{ input_fee_ppk, 64 });
159164
}

src/router/router.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ const router_handlers = @import("router_handlers.zig");
66
const zul = @import("zul");
77
const fake_wallet = @import("../fake_wallet/fake_wallet.zig");
88

9+
const MintLightning = core.lightning.MintLightning;
910
const Mint = core.mint.Mint;
1011
const CurrencyUnit = core.nuts.CurrencyUnit;
1112
const PaymentMethod = core.nuts.PaymentMethod;
12-
const FakeWallet = fake_wallet.FakeWallet;
1313

14-
pub const LnBackendsMap = std.HashMap(LnKey, FakeWallet, LnKeyContext, 80);
14+
pub const LnBackendsMap = std.HashMap(LnKey, MintLightning, LnKeyContext, 80);
1515

1616
/// Create mint [`Server`] with required endpoints for cashu mint
1717
/// Caller responsible for free resources

src/router/router_handlers.zig

+4-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const core = @import("../core/lib.zig");
44
const zul = @import("zul");
55
const ln_invoice = @import("../lightning_invoices/invoice.zig");
66

7-
const FakeWallet = @import("../fake_wallet/fake_wallet.zig").FakeWallet;
7+
const MintLightning = core.lightning.MintLightning;
88
const MintState = @import("router.zig").MintState;
99
const LnKey = @import("router.zig").LnKey;
1010

@@ -96,9 +96,7 @@ pub fn getMintBolt11Quote(
9696

9797
const payload = (try req.json(core.nuts.nut04.MintQuoteBolt11Request)) orelse return error.WrongRequest;
9898

99-
const ln: FakeWallet = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
100-
std.log.err("Bolt11 mint request for unsupported unit, unit = {any}", .{payload.unit});
101-
99+
const ln: MintLightning = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
102100
return error.UnsupportedUnit;
103101
};
104102

@@ -164,9 +162,7 @@ pub fn getMeltBolt11Quote(
164162

165163
const payload = (try req.json(core.nuts.nut05.MeltQuoteBolt11Request)) orelse return error.WrongRequest;
166164

167-
const ln: FakeWallet = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
168-
std.log.err("Bolt11 mint request for unsupported unit, unit = {any}", .{payload.unit});
169-
165+
const ln: MintLightning = state.ln.get(LnKey.init(payload.unit, .bolt11)) orelse {
170166
return error.UnsupportedUnit;
171167
};
172168

@@ -323,9 +319,7 @@ pub fn postMeltBolt11(
323319
}
324320
}
325321

326-
const ln: FakeWallet = state.ln.get(.{ .unit = quote.unit, .method = .bolt11 }) orelse {
327-
std.log.debug("Could not get ln backend for {}, bolt11 ", .{quote.unit});
328-
322+
const ln: MintLightning = state.ln.get(.{ .unit = quote.unit, .method = .bolt11 }) orelse {
329323
state.mint.processUnpaidMelt(payload) catch |e| {
330324
std.log.err("Could not reset melt quote state: {}", .{e});
331325
};

0 commit comments

Comments
 (0)