lnlink-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +461 -0
- package/dist/app.js +11165 -0
- package/dist/binaries.json +20 -0
- package/dist/build-info.json +41 -0
- package/dist/config.default.js +19 -0
- package/dist/index.js +19002 -0
- package/dist/index.js.map +7 -0
- package/dist/package.json +61 -0
- package/dist/prisma/migrations/20250918020814_/migration.sql +188 -0
- package/dist/prisma/migrations/20251114105314_auto_update/migration.sql +2 -0
- package/dist/prisma/migrations/migration_lock.toml +3 -0
- package/dist/prisma/schema.prisma +181 -0
- package/dist/proto/chainkit.proto +74 -0
- package/dist/proto/lightning.proto +5411 -0
- package/dist/proto/lit-status.proto +36 -0
- package/dist/proto/looprpc/client.proto +1435 -0
- package/dist/proto/price_oracle.proto +243 -0
- package/dist/proto/rfqrpc/rfq.proto +436 -0
- package/dist/proto/routerrpc/router.proto +1136 -0
- package/dist/proto/signrpc/signer.proto +709 -0
- package/dist/proto/stateservice.proto +73 -0
- package/dist/proto/swapserverrpc/common.proto +37 -0
- package/dist/proto/tapchannel.proto +306 -0
- package/dist/proto/tapcommon.proto +36 -0
- package/dist/proto/taprootassets.proto +1959 -0
- package/dist/proto/universe.proto +1063 -0
- package/dist/proto/walletkit.proto +1594 -0
- package/dist/proto/walletunlocker.proto +338 -0
- package/dist/public/css/initOwner.css +553 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/init.html +70 -0
- package/dist/public/js/init.js +454 -0
- package/dist/setting.mainnet.json +22 -0
- package/dist/setting.regtest.json +22 -0
- package/dist/setting.testnet.json +22 -0
- package/package.json +91 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/* global bootstrap */
|
|
2
|
+
|
|
3
|
+
// Network configuration presets
|
|
4
|
+
const networkConfigs = {
|
|
5
|
+
regtest: {
|
|
6
|
+
bitcoindIndex: "regtest.lnfi.network:50001",
|
|
7
|
+
bitcoindPass: "lnfi_pass12GA",
|
|
8
|
+
bitcoindRpcHost: "regtest.lnfi.network",
|
|
9
|
+
bitcoindRpcPort: "18443",
|
|
10
|
+
bitcoindUser: "lnfi_user",
|
|
11
|
+
bitcoindZmqBlock: "tcp://regtest.lnfi.network:28334",
|
|
12
|
+
bitcoindZmqRawTx: "tcp://regtest.lnfi.network:28335",
|
|
13
|
+
network: "regtest",
|
|
14
|
+
nostrRelays: ["wss://relay01.lnfi.network", "wss://relay02.lnfi.network"],
|
|
15
|
+
officialLndPeer: "027d2f1be71dc24c60b15070489d4ef274dd6aac236d02c67c76d6935defba56a6",
|
|
16
|
+
officialLndPeerHost: "regtest.lnfi.network:9735",
|
|
17
|
+
officialNostrPubKey: "npub1me48869w43j30cfry9ayz9dsdl4gj54xppgk9krrv7g6hsq7psuqp3yusn",
|
|
18
|
+
officialRgbPeer: "03b7153e278882e48e690acd0743305cbada86b131ab3388ccd782b45b02f064ef",
|
|
19
|
+
officialRgbPeerHost: "regtest.lnfi.network:9736",
|
|
20
|
+
officialUniverseServer: "regtest.lnfi.network:10009",
|
|
21
|
+
priceOracle: "grpc-oracle.lnfi.network",
|
|
22
|
+
rgbProxy: "rpc://regtest.lnfi.network:5000/json-rpc",
|
|
23
|
+
},
|
|
24
|
+
testnet: {
|
|
25
|
+
bitcoindIndex: "34.84.252.57:50001",
|
|
26
|
+
bitcoindPass: "rpcpassword",
|
|
27
|
+
bitcoindRpcHost: "34.84.252.57",
|
|
28
|
+
bitcoindRpcPort: "18332",
|
|
29
|
+
bitcoindUser: "bitcoinrpc",
|
|
30
|
+
bitcoindZmqBlock: "tcp://34.84.252.57:28332",
|
|
31
|
+
bitcoindZmqRawTx: "tcp://34.84.252.57:28333",
|
|
32
|
+
network: "testnet",
|
|
33
|
+
nostrRelays: ["wss://relay01.lnfi.network", "wss://relay02.lnfi.network"],
|
|
34
|
+
officialLndPeer: "02caa8ef3d3f2864451d90736ab6646d2aafdb664998dda545d5daa0c7d7fb4bad",
|
|
35
|
+
officialLndPeerHost: "34.84.252.57:9737",
|
|
36
|
+
officialNostrPubKey: "npub1me48869w43j30cfry9ayz9dsdl4gj54xppgk9krrv7g6hsq7psuqp3yusn",
|
|
37
|
+
officialRgbPeer: "03739b23a95f19ec03cea2e9dc2b498527f65e45fe4e68184cf845c893abb6ac38",
|
|
38
|
+
officialRgbPeerHost: "34.84.252.57:9736",
|
|
39
|
+
officialUniverseServer: "34.84.252.57:10009",
|
|
40
|
+
priceOracle: "grpc-oracle.lnfi.network",
|
|
41
|
+
rgbProxy: "rpc://34.84.252.57:3000/json-rpc",
|
|
42
|
+
},
|
|
43
|
+
mainnet: {
|
|
44
|
+
bitcoindIndex: "mainnet.lnfi.network:50001",
|
|
45
|
+
bitcoindPass: "lnfi_pass12GA",
|
|
46
|
+
bitcoindRpcHost: "mainnet.lnfi.network",
|
|
47
|
+
bitcoindRpcPort: "8332",
|
|
48
|
+
bitcoindUser: "lnfi_user",
|
|
49
|
+
bitcoindZmqBlock: "tcp://mainnet.lnfi.network:28334",
|
|
50
|
+
bitcoindZmqRawTx: "tcp://mainnet.lnfi.network:28335",
|
|
51
|
+
network: "mainnet",
|
|
52
|
+
nostrRelays: ["wss://relay01.lnfi.network","wss://dev-relay.lnfi.network"],
|
|
53
|
+
officialLndPeer: "027d2f1be71dc24c60b15070489d4ef274dd6aac236d02c67c76d6935defba56a6",
|
|
54
|
+
officialLndPeerHost: "mainnet.lnfi.network:9735",
|
|
55
|
+
officialNostrPubKey: "npub1me48869w43j30cfry9ayz9dsdl4gj54xppgk9krrv7g6hsq7psuqp3yusn",
|
|
56
|
+
officialRgbPeer: "03b7153e278882e48e690acd0743305cbada86b131ab3388ccd782b45b02f064ef",
|
|
57
|
+
officialRgbPeerHost: "mainnet.lnfi.network:9736",
|
|
58
|
+
officialUniverseServer: "mainnet.lnfi.network:10009",
|
|
59
|
+
priceOracle: "grpc-oracle.lnfi.network",
|
|
60
|
+
rgbProxy: "rpc://mainnet.lnfi.network:5000/json-rpc",
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Field display name mapping
|
|
65
|
+
const fieldLabels = {
|
|
66
|
+
bitcoindIndex: "Bitcoind Index",
|
|
67
|
+
bitcoindPass: "Bitcoind Password",
|
|
68
|
+
bitcoindRpcHost: "Bitcoind RPC Host",
|
|
69
|
+
bitcoindRpcPort: "Bitcoind RPC Port",
|
|
70
|
+
bitcoindUser: "Bitcoind User",
|
|
71
|
+
bitcoindZmqBlock: "Bitcoind ZMQ Block",
|
|
72
|
+
bitcoindZmqRawTx: "Bitcoind ZMQ Raw TX",
|
|
73
|
+
network: "Network",
|
|
74
|
+
nostrRelays: "Nostr Relays",
|
|
75
|
+
officialLndPeer: "Official LND Peer",
|
|
76
|
+
officialLndPeerHost: "Official LND Peer Host",
|
|
77
|
+
officialNostrPubKey: "Official Nostr PubKey",
|
|
78
|
+
officialRgbPeer: "Official RGB Peer",
|
|
79
|
+
officialRgbPeerHost: "Official RGB Peer Host",
|
|
80
|
+
officialUniverseServer: "Official Universe Server",
|
|
81
|
+
priceOracle: "Price Oracle",
|
|
82
|
+
rgbProxy: "RGB Proxy",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Show error modal
|
|
86
|
+
function showErrorModal(message) {
|
|
87
|
+
const errorModalBody = document.getElementById("errorModalBody")
|
|
88
|
+
errorModalBody.textContent = message
|
|
89
|
+
if (typeof bootstrap !== "undefined") {
|
|
90
|
+
const errorModal = new bootstrap.Modal(document.getElementById("errorModal"))
|
|
91
|
+
errorModal.show()
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.error("Error:", message)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Show success modal
|
|
99
|
+
function showSuccessModal(message) {
|
|
100
|
+
const successModalBody = document.getElementById("successModalBody")
|
|
101
|
+
successModalBody.textContent = message
|
|
102
|
+
if (typeof bootstrap !== "undefined") {
|
|
103
|
+
const successModal = new bootstrap.Modal(document.getElementById("successModal"))
|
|
104
|
+
successModal.show()
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
console.log("Success:", message)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Status determination function
|
|
112
|
+
function getStatusClass(value) {
|
|
113
|
+
const strValue = String(value).toLowerCase()
|
|
114
|
+
if (strValue === "true" || strValue === "running" || strValue === "active" || strValue === "online") {
|
|
115
|
+
return { class: "status-success", icon: "fas fa-check-circle" }
|
|
116
|
+
}
|
|
117
|
+
else if (strValue === "false" || strValue === "stopped" || strValue === "inactive" || strValue === "offline") {
|
|
118
|
+
return { class: "status-error", icon: "fas fa-times-circle" }
|
|
119
|
+
}
|
|
120
|
+
else if (strValue.includes("pending") || strValue.includes("waiting")) {
|
|
121
|
+
return { class: "status-warning", icon: "fas fa-clock" }
|
|
122
|
+
}
|
|
123
|
+
return { class: "", icon: "fas fa-info-circle" }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Get system information
|
|
127
|
+
async function getInfo() {
|
|
128
|
+
const mainContent = document.getElementById("main-content")
|
|
129
|
+
|
|
130
|
+
// Show loading state
|
|
131
|
+
mainContent.innerHTML = "<div class=\"text-center\"><div class=\"loading\"></div>Loading information...</div>"
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const res = await fetch("/api/lnd/info").then(res => res.json())
|
|
135
|
+
|
|
136
|
+
if (res.code === 200) {
|
|
137
|
+
if (res.data) {
|
|
138
|
+
const { owner, settings } = res.data
|
|
139
|
+
|
|
140
|
+
// If both owner and settings exist, show configured view
|
|
141
|
+
if (owner && settings) {
|
|
142
|
+
renderConfiguredView(res.data, settings)
|
|
143
|
+
}
|
|
144
|
+
// If missing owner or settings, show configuration form
|
|
145
|
+
else {
|
|
146
|
+
renderConfigurationForm(res.data)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (res.code === 500 && res.message === "Please init the wallet or init owner first") {
|
|
151
|
+
// If wallet/owner not initialized, show configuration form
|
|
152
|
+
renderConfigurationForm({})
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
mainContent.innerHTML = "<div class=\"alert alert-danger\"><i class=\"fas fa-exclamation-triangle\"></i> Failed to load information</div>"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
console.error("Failed to get info:", error)
|
|
160
|
+
mainContent.innerHTML = "<div class=\"alert alert-danger\"><i class=\"fas fa-exclamation-triangle\"></i> Network error occurred</div>"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Render configured view (when both owner and settings exist)
|
|
165
|
+
function renderConfiguredView(basicData, settings) {
|
|
166
|
+
const mainContent = document.getElementById("main-content")
|
|
167
|
+
const networkType = settings.network || "regtest"
|
|
168
|
+
|
|
169
|
+
const html = `
|
|
170
|
+
<!-- Basic Information Section -->
|
|
171
|
+
<div class="info-section">
|
|
172
|
+
<div class="info-title">
|
|
173
|
+
<i class="fas fa-server"></i>
|
|
174
|
+
System Information
|
|
175
|
+
</div>
|
|
176
|
+
<ul class="list-group">
|
|
177
|
+
${renderBasicInfoList(basicData)}
|
|
178
|
+
</ul>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<!-- Advanced Configuration Section -->
|
|
182
|
+
<div class="info-section">
|
|
183
|
+
<div class="info-title">
|
|
184
|
+
<i class="fas fa-cogs"></i>
|
|
185
|
+
Configuration Settings
|
|
186
|
+
<span class="network-indicator network-${networkType}">${networkType}</span>
|
|
187
|
+
</div>
|
|
188
|
+
<ul class="list-group">
|
|
189
|
+
${renderSettingsList(settings)}
|
|
190
|
+
</ul>
|
|
191
|
+
</div>
|
|
192
|
+
`
|
|
193
|
+
|
|
194
|
+
mainContent.innerHTML = html
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Render configuration form (when owner or settings missing)
|
|
198
|
+
function renderConfigurationForm(basicData) {
|
|
199
|
+
const mainContent = document.getElementById("main-content")
|
|
200
|
+
|
|
201
|
+
const html = `
|
|
202
|
+
<div class="info-section">
|
|
203
|
+
<div class="info-title">
|
|
204
|
+
<i class="fas fa-cog"></i>
|
|
205
|
+
Initial Configuration
|
|
206
|
+
</div>
|
|
207
|
+
<form class="needs-validation" novalidate id="configForm" autocomplete="off">
|
|
208
|
+
<!-- Owner Configuration -->
|
|
209
|
+
<div class="config-group">
|
|
210
|
+
<h6><i class="fas fa-user"></i> Owner Configuration</h6>
|
|
211
|
+
<div class="mb-3">
|
|
212
|
+
<label for="owner" class="form-label">Owner Address</label>
|
|
213
|
+
<input type="text" class="form-control" id="owner" name="owner" required
|
|
214
|
+
placeholder="Enter owner address" value="${basicData?.owner || ""}">
|
|
215
|
+
<div class="valid-feedback">
|
|
216
|
+
<i class="fas fa-check"></i> Looks good!
|
|
217
|
+
</div>
|
|
218
|
+
<div class="invalid-feedback">
|
|
219
|
+
<i class="fas fa-times"></i> Please provide a valid owner address.
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
<!-- Network Configuration -->
|
|
225
|
+
<div class="config-group mt-3">
|
|
226
|
+
<h6><i class="fas fa-network-wired"></i> Network Configuration</h6>
|
|
227
|
+
<div class="mb-3">
|
|
228
|
+
<label for="network" class="form-label">Network Type</label>
|
|
229
|
+
<select class="form-select" id="network" name="network" required onchange="updateConfigFields()">
|
|
230
|
+
<option value="regtest">Regtest</option>
|
|
231
|
+
<option value="testnet">Testnet</option>
|
|
232
|
+
<option value="mainnet">Mainnet</option>
|
|
233
|
+
</select>
|
|
234
|
+
<div class="valid-feedback">
|
|
235
|
+
<i class="fas fa-check"></i> Network type selected!
|
|
236
|
+
</div>
|
|
237
|
+
<div class="invalid-feedback">
|
|
238
|
+
<i class="fas fa-times"></i> Please select network type.
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<!-- Dynamic Configuration Fields -->
|
|
244
|
+
<div id="config-fields-container"></div>
|
|
245
|
+
|
|
246
|
+
<div class="row mb-3 mt-4 d-flex justify-content-center">
|
|
247
|
+
<button type="submit" id="btn_config_submit" class="btn btn-primary" style="width:250px">
|
|
248
|
+
<i class="fas fa-save"></i> Save Complete Configuration
|
|
249
|
+
</button>
|
|
250
|
+
</div>
|
|
251
|
+
</form>
|
|
252
|
+
</div>
|
|
253
|
+
`
|
|
254
|
+
|
|
255
|
+
mainContent.innerHTML = html
|
|
256
|
+
|
|
257
|
+
// Initialize configuration fields
|
|
258
|
+
updateConfigFields()
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Render basic information list
|
|
262
|
+
function renderBasicInfoList(data) {
|
|
263
|
+
let html = ""
|
|
264
|
+
const excludeKeys = ["settings"]
|
|
265
|
+
|
|
266
|
+
for (const key in data) {
|
|
267
|
+
if (excludeKeys.includes(key))
|
|
268
|
+
continue
|
|
269
|
+
|
|
270
|
+
const value = data[key]
|
|
271
|
+
const status = getStatusClass(value)
|
|
272
|
+
|
|
273
|
+
let valueHtml = `<span class="info-value ${status.class}">
|
|
274
|
+
<i class="${status.icon} status-icon"></i>${value}
|
|
275
|
+
</span>`
|
|
276
|
+
|
|
277
|
+
if (key === "manageUrl") {
|
|
278
|
+
valueHtml = `<span class="info-value">
|
|
279
|
+
<a href="${value}" class="info-link" target="_self">
|
|
280
|
+
<i class="fas fa-external-link-alt status-icon"></i>Click to manage
|
|
281
|
+
</a>
|
|
282
|
+
</span>`
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
html += `
|
|
286
|
+
<li class="list-group-item">
|
|
287
|
+
<div class="info-key">${key}:</div>
|
|
288
|
+
<div class="info-value-container">${valueHtml}</div>
|
|
289
|
+
</li>
|
|
290
|
+
`
|
|
291
|
+
}
|
|
292
|
+
return html
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Render settings list
|
|
296
|
+
function renderSettingsList(settings) {
|
|
297
|
+
let html = ""
|
|
298
|
+
for (const key in settings) {
|
|
299
|
+
const value = Array.isArray(settings[key]) ? settings[key].join(", ") : settings[key]
|
|
300
|
+
const label = fieldLabels[key] || key
|
|
301
|
+
|
|
302
|
+
html += `
|
|
303
|
+
<li class="list-group-item">
|
|
304
|
+
<div class="info-key">${label}:</div>
|
|
305
|
+
<div class="info-value-container">
|
|
306
|
+
<span class="info-value">${value}</span>
|
|
307
|
+
</div>
|
|
308
|
+
</li>
|
|
309
|
+
`
|
|
310
|
+
}
|
|
311
|
+
return html
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Update configuration fields
|
|
315
|
+
function updateConfigFields() {
|
|
316
|
+
const networkSelect = document.getElementById("network")
|
|
317
|
+
const container = document.getElementById("config-fields-container")
|
|
318
|
+
|
|
319
|
+
if (!networkSelect || !container)
|
|
320
|
+
return
|
|
321
|
+
|
|
322
|
+
const selectedNetwork = networkSelect.value
|
|
323
|
+
const config = networkConfigs[selectedNetwork]
|
|
324
|
+
|
|
325
|
+
if (!config)
|
|
326
|
+
return
|
|
327
|
+
|
|
328
|
+
let fieldsHtml = "<div class=\"config-grid\">"
|
|
329
|
+
|
|
330
|
+
// Group fields by category
|
|
331
|
+
const groups = {
|
|
332
|
+
"Bitcoin Configuration": ["bitcoindRpcHost", "bitcoindRpcPort", "bitcoindUser", "bitcoindPass", "bitcoindIndex", "bitcoindZmqBlock", "bitcoindZmqRawTx"],
|
|
333
|
+
"LND Configuration": ["officialLndPeer", "officialLndPeerHost", "officialUniverseServer"],
|
|
334
|
+
"RGB Configuration": ["officialRgbPeer", "officialRgbPeerHost", "rgbProxy"],
|
|
335
|
+
"Nostr Configuration": ["officialNostrPubKey", "nostrRelays"],
|
|
336
|
+
"Other Configuration": ["priceOracle"],
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
for (const groupName in groups) {
|
|
340
|
+
fieldsHtml += `<div class="config-group">`
|
|
341
|
+
fieldsHtml += `<h6><i class="fas fa-cog"></i> ${groupName}</h6>`
|
|
342
|
+
|
|
343
|
+
groups[groupName].forEach((key) => {
|
|
344
|
+
if (config[key] !== undefined) {
|
|
345
|
+
const label = fieldLabels[key] || key
|
|
346
|
+
const value = Array.isArray(config[key]) ? config[key].join(",") : config[key]
|
|
347
|
+
|
|
348
|
+
fieldsHtml += `
|
|
349
|
+
<div class="mb-3">
|
|
350
|
+
<label for="${key}" class="form-label">${label}</label>
|
|
351
|
+
<input type="text" class="form-control" id="${key}" name="${key}"
|
|
352
|
+
value="${value}" required>
|
|
353
|
+
<div class="valid-feedback">
|
|
354
|
+
<i class="fas fa-check"></i> Configuration correct!
|
|
355
|
+
</div>
|
|
356
|
+
<div class="invalid-feedback">
|
|
357
|
+
<i class="fas fa-times"></i> Please enter ${label}.
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
`
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
fieldsHtml += `</div>`
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
fieldsHtml += "</div>"
|
|
368
|
+
container.innerHTML = fieldsHtml
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Handle configuration form submission
|
|
372
|
+
async function handleConfigFormSubmit(event) {
|
|
373
|
+
event.preventDefault()
|
|
374
|
+
const form = document.getElementById("configForm")
|
|
375
|
+
const submitBtn = document.getElementById("btn_config_submit")
|
|
376
|
+
|
|
377
|
+
if (!form.checkValidity()) {
|
|
378
|
+
event.stopPropagation()
|
|
379
|
+
form.classList.add("was-validated")
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
form.classList.add("was-validated")
|
|
384
|
+
submitBtn.setAttribute("disabled", "disabled")
|
|
385
|
+
submitBtn.innerHTML = "<div class=\"loading\"></div>Saving..."
|
|
386
|
+
|
|
387
|
+
const formData = new FormData(form)
|
|
388
|
+
const myHeaders = new Headers()
|
|
389
|
+
myHeaders.append("Content-Type", "application/json")
|
|
390
|
+
|
|
391
|
+
// Extract owner
|
|
392
|
+
const owner = formData.get("owner")
|
|
393
|
+
|
|
394
|
+
// Build settings object (exclude owner)
|
|
395
|
+
const settings = {}
|
|
396
|
+
for (const [key, value] of formData.entries()) {
|
|
397
|
+
if (key === "owner")
|
|
398
|
+
continue
|
|
399
|
+
|
|
400
|
+
if (key === "nostrRelays") {
|
|
401
|
+
// Handle comma-separated array
|
|
402
|
+
settings[key] = value.split(",").map(item => item.trim()).filter(item => item)
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
settings[key] = value
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const raw = JSON.stringify({
|
|
410
|
+
owner,
|
|
411
|
+
settings,
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
const requestOptions = {
|
|
415
|
+
method: "POST",
|
|
416
|
+
headers: myHeaders,
|
|
417
|
+
body: raw,
|
|
418
|
+
redirect: "follow",
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
const response = await fetch("/api/lnd/init", requestOptions)
|
|
423
|
+
const result = await response.json()
|
|
424
|
+
|
|
425
|
+
if (result.code === 200) {
|
|
426
|
+
await getInfo()
|
|
427
|
+
showSuccessModal("Complete configuration saved successfully!")
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
showErrorModal(result.message || "Configuration failed")
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
console.error("Network error:", error)
|
|
435
|
+
showErrorModal("Network error occurred")
|
|
436
|
+
}
|
|
437
|
+
finally {
|
|
438
|
+
submitBtn.removeAttribute("disabled")
|
|
439
|
+
submitBtn.innerHTML = "<i class=\"fas fa-save\"></i> Save Complete Configuration"
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Page initialization
|
|
444
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
445
|
+
// Get information
|
|
446
|
+
await getInfo()
|
|
447
|
+
|
|
448
|
+
// Bind form submission events (using event delegation)
|
|
449
|
+
document.addEventListener("submit", (event) => {
|
|
450
|
+
if (event.target.id === "configForm") {
|
|
451
|
+
handleConfigFormSubmit(event)
|
|
452
|
+
}
|
|
453
|
+
})
|
|
454
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bitcoindIndex": "CHANGE_ME_MAINNET_ELECTRS_HOST:50001",
|
|
3
|
+
"bitcoindPass": "CHANGE_ME_MAINNET_RPC_PASSWORD",
|
|
4
|
+
"bitcoindRpcHost": "CHANGE_ME_MAINNET_BITCOIND_HOST",
|
|
5
|
+
"bitcoindRpcPort": "8332",
|
|
6
|
+
"bitcoindUser": "CHANGE_ME_MAINNET_RPC_USER",
|
|
7
|
+
"bitcoindZmqBlock": "tcp://CHANGE_ME_MAINNET_BITCOIND_HOST:28334",
|
|
8
|
+
"bitcoindZmqRawTx": "tcp://CHANGE_ME_MAINNET_BITCOIND_HOST:28335",
|
|
9
|
+
"network": "mainnet",
|
|
10
|
+
"nostrRelays": [
|
|
11
|
+
"wss://CHANGE_ME_MAINNET_RELAY_1",
|
|
12
|
+
"wss://CHANGE_ME_MAINNET_RELAY_2"
|
|
13
|
+
],
|
|
14
|
+
"officialLndPeer": "",
|
|
15
|
+
"officialLndPeerHost": "CHANGE_ME_MAINNET_LND_HOST:9735",
|
|
16
|
+
"officialNostrPubKey": "",
|
|
17
|
+
"officialRgbPeer": "",
|
|
18
|
+
"officialRgbPeerHost": "CHANGE_ME_MAINNET_RGB_HOST:9736",
|
|
19
|
+
"officialUniverseServer": "CHANGE_ME_MAINNET_UNIVERSE_HOST:10009",
|
|
20
|
+
"priceOracle": "grpc-oracle.lnfi.network",
|
|
21
|
+
"rgbProxy": "rpc://CHANGE_ME_MAINNET_RGB_PROXY_HOST:5000/json-rpc"
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bitcoindIndex": "regtest.lnfi.network:50001",
|
|
3
|
+
"bitcoindPass": "lnfi_pass12GA",
|
|
4
|
+
"bitcoindRpcHost": "regtest.lnfi.network",
|
|
5
|
+
"bitcoindRpcPort": "18443",
|
|
6
|
+
"bitcoindUser": "lnfi_user",
|
|
7
|
+
"bitcoindZmqBlock": "tcp://regtest.lnfi.network:28334",
|
|
8
|
+
"bitcoindZmqRawTx": "tcp://regtest.lnfi.network:28335",
|
|
9
|
+
"network": "regtest",
|
|
10
|
+
"nostrRelays": [
|
|
11
|
+
"wss://relay01.lnfi.network",
|
|
12
|
+
"wss://dev-relay.lnfi.network"
|
|
13
|
+
],
|
|
14
|
+
"officialLndPeer": "03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3",
|
|
15
|
+
"officialLndPeerHost": "34.84.66.29:7739",
|
|
16
|
+
"officialNostrPubKey": "npub1me48869w43j30cfry9ayz9dsdl4gj54xppgk9krrv7g6hsq7psuqp3yusn",
|
|
17
|
+
"officialRgbPeer": "03b7153e278882e48e690acd0743305cbada86b131ab3388ccd782b45b02f064ef",
|
|
18
|
+
"officialRgbPeerHost": "regtest.lnfi.network:9736",
|
|
19
|
+
"officialUniverseServer": "regtest.lnfi.network:10009",
|
|
20
|
+
"priceOracle": "grpc-oracle.lnfi.network",
|
|
21
|
+
"rgbProxy": "rpc://regtest.lnfi.network:5000/json-rpc"
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bitcoindIndex": "CHANGE_ME_TESTNET_ELECTRS_HOST:50001",
|
|
3
|
+
"bitcoindPass": "CHANGE_ME_TESTNET_RPC_PASSWORD",
|
|
4
|
+
"bitcoindRpcHost": "CHANGE_ME_TESTNET_BITCOIND_HOST",
|
|
5
|
+
"bitcoindRpcPort": "18332",
|
|
6
|
+
"bitcoindUser": "CHANGE_ME_TESTNET_RPC_USER",
|
|
7
|
+
"bitcoindZmqBlock": "tcp://CHANGE_ME_TESTNET_BITCOIND_HOST:28334",
|
|
8
|
+
"bitcoindZmqRawTx": "tcp://CHANGE_ME_TESTNET_BITCOIND_HOST:28335",
|
|
9
|
+
"network": "testnet",
|
|
10
|
+
"nostrRelays": [
|
|
11
|
+
"wss://CHANGE_ME_TESTNET_RELAY_1",
|
|
12
|
+
"wss://CHANGE_ME_TESTNET_RELAY_2"
|
|
13
|
+
],
|
|
14
|
+
"officialLndPeer": "",
|
|
15
|
+
"officialLndPeerHost": "CHANGE_ME_TESTNET_LND_HOST:9735",
|
|
16
|
+
"officialNostrPubKey": "",
|
|
17
|
+
"officialRgbPeer": "",
|
|
18
|
+
"officialRgbPeerHost": "CHANGE_ME_TESTNET_RGB_HOST:9736",
|
|
19
|
+
"officialUniverseServer": "CHANGE_ME_TESTNET_UNIVERSE_HOST:10009",
|
|
20
|
+
"priceOracle": "grpc-oracle.lnfi.network",
|
|
21
|
+
"rgbProxy": "rpc://CHANGE_ME_TESTNET_RGB_PROXY_HOST:5000/json-rpc"
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lnlink-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"README.md"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "node build.js && node build.js --mode development --external all --entry electron",
|
|
12
|
+
"start:bin": "dotenv -e .env.bin -- sh -c \"prisma generate && (prisma migrate dev --name auto_update || prisma db push) && node ./scripts/binSetup.js && node ./app.js\"",
|
|
13
|
+
"start:docker:dev": "dotenv -e .env.dev -- docker compose -f ./docker-compose.dev.yml up --build",
|
|
14
|
+
"start:dev": "dotenv -e .env.dev -- sh -c \"prisma generate && (prisma migrate dev --name auto_update || prisma db push) && clinic heapprof -- node ./app.js\"",
|
|
15
|
+
"start:regtest": "docker compose --env-file ./.env.regtest -f ./docker-compose-lnlink.yml up --build",
|
|
16
|
+
"start:testnet": "docker compose --env-file ./.env.testnet -f ./docker-compose-lnlink.yml up --build",
|
|
17
|
+
"start:mainnet": "docker compose --env-file ./.env.mainnet -f ./docker-compose-lnlink.yml up --build",
|
|
18
|
+
"start:bin:dist": "dotenv -e .env.bin -- sh -c \"prisma generate && prisma migrate deploy && node ./scripts/binSetup.js && node ./dist/index.js\"",
|
|
19
|
+
"lint": "eslint .",
|
|
20
|
+
"lint:fix": "eslint . --fix",
|
|
21
|
+
"lint:staged": "lint-staged",
|
|
22
|
+
"preinstall": "npx husky"
|
|
23
|
+
},
|
|
24
|
+
"_moduleAliases": {
|
|
25
|
+
"@api": "api",
|
|
26
|
+
"@constants": "constants",
|
|
27
|
+
"@business": "business",
|
|
28
|
+
"@nostr": "nostr",
|
|
29
|
+
"@package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@grpc/grpc-js": "^1.10.8",
|
|
33
|
+
"@grpc/proto-loader": "^0.7.9",
|
|
34
|
+
"@lightsparkdev/lightspark-sdk": "^1.8.9",
|
|
35
|
+
"@lnfi-network/rgb-api-js-sdk": "^1.0.7",
|
|
36
|
+
"@prisma/client": "6.14.0",
|
|
37
|
+
"axios": "^1.7.2",
|
|
38
|
+
"bitcoin-core": "^4.2.0",
|
|
39
|
+
"body-parser": "^1.20.2",
|
|
40
|
+
"cookie-parser": "~1.4.4",
|
|
41
|
+
"crypto-js": "^4.2.0",
|
|
42
|
+
"dayjs": "^1.11.10",
|
|
43
|
+
"debug": "~2.6.9",
|
|
44
|
+
"decimal.js": "^10.4.3",
|
|
45
|
+
"ethers": "^6.15.0",
|
|
46
|
+
"express": "^4.18.2",
|
|
47
|
+
"express-rate-limit": "^8.0.1",
|
|
48
|
+
"find-process": "^2.0.0",
|
|
49
|
+
"form-data": "^4.0.2",
|
|
50
|
+
"http-errors": "~1.6.3",
|
|
51
|
+
"jest": "^29.6.2",
|
|
52
|
+
"long": "^5.2.3",
|
|
53
|
+
"module-alias": "^2.2.3",
|
|
54
|
+
"morgan": "~1.9.1",
|
|
55
|
+
"node-cache": "^5.1.2",
|
|
56
|
+
"node-cron": "^3.0.3",
|
|
57
|
+
"nostr-tools": "1.17.0",
|
|
58
|
+
"pino": "^9.9.0",
|
|
59
|
+
"pino-pretty": "^13.1.1",
|
|
60
|
+
"pino-roll": "^3.1.0",
|
|
61
|
+
"prisma": "^6.14.0",
|
|
62
|
+
"typescript": "^5.7.3",
|
|
63
|
+
"ws": "^8.18.0"
|
|
64
|
+
},
|
|
65
|
+
"lint-staged": {
|
|
66
|
+
"*.ts": [
|
|
67
|
+
"eslint --fix",
|
|
68
|
+
"git add"
|
|
69
|
+
],
|
|
70
|
+
"*.js": [
|
|
71
|
+
"eslint --fix",
|
|
72
|
+
"git add"
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@antfu/eslint-config": "^4.3.0",
|
|
77
|
+
"@commitlint/cli": "^19.7.1",
|
|
78
|
+
"@commitlint/config-conventional": "^19.7.1",
|
|
79
|
+
"dotenv-cli": "^10.0.0",
|
|
80
|
+
"electron-rebuild": "^3.2.9",
|
|
81
|
+
"esbuild": "^0.25.9",
|
|
82
|
+
"eslint": "^9.20.1",
|
|
83
|
+
"husky": "^9.1.7",
|
|
84
|
+
"lint-staged": "^15.4.3",
|
|
85
|
+
"nodemon": "^3.0.3",
|
|
86
|
+
"protobufjs": "^7.2.5"
|
|
87
|
+
},
|
|
88
|
+
"engines": {
|
|
89
|
+
"node": ">=19.0.0"
|
|
90
|
+
}
|
|
91
|
+
}
|