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.
Files changed (36) hide show
  1. package/README.md +461 -0
  2. package/dist/app.js +11165 -0
  3. package/dist/binaries.json +20 -0
  4. package/dist/build-info.json +41 -0
  5. package/dist/config.default.js +19 -0
  6. package/dist/index.js +19002 -0
  7. package/dist/index.js.map +7 -0
  8. package/dist/package.json +61 -0
  9. package/dist/prisma/migrations/20250918020814_/migration.sql +188 -0
  10. package/dist/prisma/migrations/20251114105314_auto_update/migration.sql +2 -0
  11. package/dist/prisma/migrations/migration_lock.toml +3 -0
  12. package/dist/prisma/schema.prisma +181 -0
  13. package/dist/proto/chainkit.proto +74 -0
  14. package/dist/proto/lightning.proto +5411 -0
  15. package/dist/proto/lit-status.proto +36 -0
  16. package/dist/proto/looprpc/client.proto +1435 -0
  17. package/dist/proto/price_oracle.proto +243 -0
  18. package/dist/proto/rfqrpc/rfq.proto +436 -0
  19. package/dist/proto/routerrpc/router.proto +1136 -0
  20. package/dist/proto/signrpc/signer.proto +709 -0
  21. package/dist/proto/stateservice.proto +73 -0
  22. package/dist/proto/swapserverrpc/common.proto +37 -0
  23. package/dist/proto/tapchannel.proto +306 -0
  24. package/dist/proto/tapcommon.proto +36 -0
  25. package/dist/proto/taprootassets.proto +1959 -0
  26. package/dist/proto/universe.proto +1063 -0
  27. package/dist/proto/walletkit.proto +1594 -0
  28. package/dist/proto/walletunlocker.proto +338 -0
  29. package/dist/public/css/initOwner.css +553 -0
  30. package/dist/public/favicon.ico +0 -0
  31. package/dist/public/init.html +70 -0
  32. package/dist/public/js/init.js +454 -0
  33. package/dist/setting.mainnet.json +22 -0
  34. package/dist/setting.regtest.json +22 -0
  35. package/dist/setting.testnet.json +22 -0
  36. 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
+ }