lnlink-server 1.1.6 → 1.1.8
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/dist/app.js +314 -314
- package/dist/build-info.json +1 -1
- package/dist/config.default.js +1 -0
- package/dist/index.js +829 -49
- package/dist/index.js.map +4 -4
- package/dist/package.json +1 -1
- package/dist/prisma/migrations/20260402072918_add_exchange_orders/migration.sql +25 -0
- package/dist/prisma/migrations/20260403022951_auto_update/migration.sql +27 -0
- package/dist/prisma/schema.prisma +21 -0
- package/dist/public/js/init.js +125 -90
- package/dist/setting.mainnet.json +2 -1
- package/dist/setting.regtest.json +4 -4
- package/dist/setting.testnet.json +2 -1
- package/package.json +2 -2
- package/prisma/migrations/20260402072918_add_exchange_orders/migration.sql +25 -0
- package/prisma/migrations/20260403022951_auto_update/migration.sql +27 -0
- package/prisma/schema.prisma +21 -0
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var require_config_default = __commonJS({
|
|
|
22
22
|
LINK_DATA_PATH: "",
|
|
23
23
|
LINK_FLASH_SITE_BASE_URL: "https://devofflash.unift.xyz",
|
|
24
24
|
LINK_LNFI_NODE_SITE_URL: "https://devoflnnode.unift.xyz",
|
|
25
|
+
LINK_RGB_PRICE_SERVER_URL: "https://api-oracle.lnfi.network",
|
|
25
26
|
LINK_OWNER: "",
|
|
26
27
|
LINK_SETTING_FILE_PATH: ""
|
|
27
28
|
// LINK_SETTING_FILE_PATH: "",
|
|
@@ -880,7 +881,9 @@ var require_constants = __commonJS({
|
|
|
880
881
|
"link_status",
|
|
881
882
|
"list_unspents",
|
|
882
883
|
"decode_rgb_invoice",
|
|
883
|
-
"decode_ln_invoice"
|
|
884
|
+
"decode_ln_invoice",
|
|
885
|
+
"get_exchange_rate",
|
|
886
|
+
"list_exchange_orders"
|
|
884
887
|
];
|
|
885
888
|
var OWNER_PERMISSIONS = [
|
|
886
889
|
"genseed",
|
|
@@ -922,6 +925,7 @@ var require_constants = __commonJS({
|
|
|
922
925
|
"pay_rgb_invoice",
|
|
923
926
|
"disconnect_peer",
|
|
924
927
|
"create_invoice",
|
|
928
|
+
"create_hodl_invoice",
|
|
925
929
|
"pay_invoice",
|
|
926
930
|
"backup_node",
|
|
927
931
|
"restore_node",
|
|
@@ -1286,6 +1290,163 @@ var require_events = __commonJS({
|
|
|
1286
1290
|
}
|
|
1287
1291
|
});
|
|
1288
1292
|
|
|
1293
|
+
// business/service/prisma/repositories/exchangeOrderRepository.js
|
|
1294
|
+
var require_exchangeOrderRepository = __commonJS({
|
|
1295
|
+
"business/service/prisma/repositories/exchangeOrderRepository.js"(exports2, module2) {
|
|
1296
|
+
var PrismaService = require_prismaService();
|
|
1297
|
+
var ExchangeOrderRepository = class {
|
|
1298
|
+
static {
|
|
1299
|
+
__name(this, "ExchangeOrderRepository");
|
|
1300
|
+
}
|
|
1301
|
+
constructor() {
|
|
1302
|
+
this.prisma = PrismaService.getInstance().getClient();
|
|
1303
|
+
}
|
|
1304
|
+
async createOrder(data) {
|
|
1305
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1306
|
+
return this.prisma.exchangeOrder.create({
|
|
1307
|
+
data: {
|
|
1308
|
+
payment_hash: data.payment_hash,
|
|
1309
|
+
btc_invoice: data.btc_invoice,
|
|
1310
|
+
btc_amount: data.btc_amount,
|
|
1311
|
+
rgb_invoice: data.rgb_invoice || null,
|
|
1312
|
+
asset_id: data.asset_id,
|
|
1313
|
+
asset_amount: data.asset_amount,
|
|
1314
|
+
preimage: data.preimage || null,
|
|
1315
|
+
status: data.status,
|
|
1316
|
+
error_message: data.error_message || null,
|
|
1317
|
+
htlc_expiry_at: data.htlc_expiry_at,
|
|
1318
|
+
created_at: data.created_at || now,
|
|
1319
|
+
updated_at: data.updated_at || now
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
async getOrderById(id) {
|
|
1324
|
+
return this.prisma.exchangeOrder.findUnique({ where: { id } });
|
|
1325
|
+
}
|
|
1326
|
+
async getOrderByPaymentHash(payment_hash) {
|
|
1327
|
+
return this.prisma.exchangeOrder.findUnique({ where: { payment_hash } });
|
|
1328
|
+
}
|
|
1329
|
+
async getOrdersByStatus(status) {
|
|
1330
|
+
return this.prisma.exchangeOrder.findMany({
|
|
1331
|
+
where: { status },
|
|
1332
|
+
orderBy: { created_at: "asc" }
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
async getOrders({
|
|
1336
|
+
status,
|
|
1337
|
+
page = 1,
|
|
1338
|
+
page_size = 20
|
|
1339
|
+
} = {}) {
|
|
1340
|
+
const where = status ? { status } : {};
|
|
1341
|
+
const [list, total] = await Promise.all([
|
|
1342
|
+
this.prisma.exchangeOrder.findMany({
|
|
1343
|
+
where,
|
|
1344
|
+
orderBy: { created_at: "desc" },
|
|
1345
|
+
skip: (page - 1) * page_size,
|
|
1346
|
+
take: page_size
|
|
1347
|
+
}),
|
|
1348
|
+
this.prisma.exchangeOrder.count({ where })
|
|
1349
|
+
]);
|
|
1350
|
+
return { list, total };
|
|
1351
|
+
}
|
|
1352
|
+
async updateOrder(id, data) {
|
|
1353
|
+
return this.prisma.exchangeOrder.update({
|
|
1354
|
+
where: { id },
|
|
1355
|
+
data: {
|
|
1356
|
+
...data,
|
|
1357
|
+
updated_at: Math.floor(Date.now() / 1e3)
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Optimistic lock: only update if current status matches expectedStatus.
|
|
1363
|
+
* Returns true if update succeeded, false if status already changed.
|
|
1364
|
+
*/
|
|
1365
|
+
async updateOrderWithExpectedStatus(id, expectedStatus, data) {
|
|
1366
|
+
const result = await this.prisma.exchangeOrder.updateMany({
|
|
1367
|
+
where: { id, status: expectedStatus },
|
|
1368
|
+
data: {
|
|
1369
|
+
...data,
|
|
1370
|
+
updated_at: Math.floor(Date.now() / 1e3)
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
return result.count > 0;
|
|
1374
|
+
}
|
|
1375
|
+
async getOrdersByStatusIn(statuses) {
|
|
1376
|
+
return this.prisma.exchangeOrder.findMany({
|
|
1377
|
+
where: { status: { in: statuses } },
|
|
1378
|
+
orderBy: { created_at: "asc" }
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
module2.exports = ExchangeOrderRepository;
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
// business/service/prisma/db/exchangeOrders.js
|
|
1387
|
+
var require_exchangeOrders = __commonJS({
|
|
1388
|
+
"business/service/prisma/db/exchangeOrders.js"(exports2, module2) {
|
|
1389
|
+
var Logger = require_linkLogger();
|
|
1390
|
+
var ExchangeOrderRepository = require_exchangeOrderRepository();
|
|
1391
|
+
var repo = null;
|
|
1392
|
+
function getRepo() {
|
|
1393
|
+
if (!repo) {
|
|
1394
|
+
repo = new ExchangeOrderRepository();
|
|
1395
|
+
}
|
|
1396
|
+
return repo;
|
|
1397
|
+
}
|
|
1398
|
+
__name(getRepo, "getRepo");
|
|
1399
|
+
module2.exports = {
|
|
1400
|
+
createExchangeOrder: /* @__PURE__ */ __name(async (data) => {
|
|
1401
|
+
const logger2 = new Logger("exchangeOrderDB");
|
|
1402
|
+
try {
|
|
1403
|
+
return await getRepo().createOrder(data);
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
logger2.error("Error creating exchange order:", error.message);
|
|
1406
|
+
throw error;
|
|
1407
|
+
}
|
|
1408
|
+
}, "createExchangeOrder"),
|
|
1409
|
+
getExchangeOrderById: /* @__PURE__ */ __name(async (id) => {
|
|
1410
|
+
return getRepo().getOrderById(id);
|
|
1411
|
+
}, "getExchangeOrderById"),
|
|
1412
|
+
getExchangeOrderByPaymentHash: /* @__PURE__ */ __name(async (payment_hash) => {
|
|
1413
|
+
return getRepo().getOrderByPaymentHash(payment_hash);
|
|
1414
|
+
}, "getExchangeOrderByPaymentHash"),
|
|
1415
|
+
getExchangeOrdersByStatus: /* @__PURE__ */ __name(async (status) => {
|
|
1416
|
+
return getRepo().getOrdersByStatus(status);
|
|
1417
|
+
}, "getExchangeOrdersByStatus"),
|
|
1418
|
+
getExchangeOrdersByStatusIn: /* @__PURE__ */ __name(async (statuses) => {
|
|
1419
|
+
return getRepo().getOrdersByStatusIn(statuses);
|
|
1420
|
+
}, "getExchangeOrdersByStatusIn"),
|
|
1421
|
+
getExchangeOrders: /* @__PURE__ */ __name(async (filters) => {
|
|
1422
|
+
return getRepo().getOrders(filters);
|
|
1423
|
+
}, "getExchangeOrders"),
|
|
1424
|
+
updateExchangeOrder: /* @__PURE__ */ __name(async (id, data) => {
|
|
1425
|
+
const logger2 = new Logger("exchangeOrderDB");
|
|
1426
|
+
try {
|
|
1427
|
+
return await getRepo().updateOrder(id, data);
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
logger2.error("Error updating exchange order:", error.message);
|
|
1430
|
+
throw error;
|
|
1431
|
+
}
|
|
1432
|
+
}, "updateExchangeOrder"),
|
|
1433
|
+
/**
|
|
1434
|
+
* Optimistic lock update: only succeeds if current status matches expectedStatus.
|
|
1435
|
+
* Returns true if updated, false if status already changed (stale).
|
|
1436
|
+
*/
|
|
1437
|
+
updateExchangeOrderWithExpectedStatus: /* @__PURE__ */ __name(async (id, expectedStatus, data) => {
|
|
1438
|
+
const logger2 = new Logger("exchangeOrderDB");
|
|
1439
|
+
try {
|
|
1440
|
+
return await getRepo().updateOrderWithExpectedStatus(id, expectedStatus, data);
|
|
1441
|
+
} catch (error) {
|
|
1442
|
+
logger2.error("Error updating exchange order (optimistic):", error.message);
|
|
1443
|
+
throw error;
|
|
1444
|
+
}
|
|
1445
|
+
}, "updateExchangeOrderWithExpectedStatus")
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
});
|
|
1449
|
+
|
|
1289
1450
|
// business/service/prisma/repositories/orderRepository.js
|
|
1290
1451
|
var require_orderRepository = __commonJS({
|
|
1291
1452
|
"business/service/prisma/repositories/orderRepository.js"(exports2, module2) {
|
|
@@ -2532,6 +2693,7 @@ var require_dbService = __commonJS({
|
|
|
2532
2693
|
"business/service/prisma/dbService.js"(exports2, module2) {
|
|
2533
2694
|
var config = require_config();
|
|
2534
2695
|
var events = require_events();
|
|
2696
|
+
var exchangeOrders = require_exchangeOrders();
|
|
2535
2697
|
var orders = require_orders();
|
|
2536
2698
|
var transactions = require_transactions();
|
|
2537
2699
|
var users = require_users();
|
|
@@ -2542,6 +2704,7 @@ var require_dbService = __commonJS({
|
|
|
2542
2704
|
...users,
|
|
2543
2705
|
...transactions,
|
|
2544
2706
|
...orders,
|
|
2707
|
+
...exchangeOrders,
|
|
2545
2708
|
...utils
|
|
2546
2709
|
};
|
|
2547
2710
|
}
|
|
@@ -2651,6 +2814,7 @@ var require_getConfig = __commonJS({
|
|
|
2651
2814
|
officialUniverseServer,
|
|
2652
2815
|
priceOracle,
|
|
2653
2816
|
rgbProxy,
|
|
2817
|
+
rgbPriceServer,
|
|
2654
2818
|
enableTor
|
|
2655
2819
|
} = settingFileData;
|
|
2656
2820
|
const litdRgbConfig = {
|
|
@@ -2667,6 +2831,7 @@ var require_getConfig = __commonJS({
|
|
|
2667
2831
|
LINK_RGB_BITCOIND_RPCPASS: bitcoindPass,
|
|
2668
2832
|
LINK_RGB_ELECTRS_HOST: bitcoindIndex,
|
|
2669
2833
|
LINK_RGB_PROXY_ENDPOINT: rgbProxy,
|
|
2834
|
+
LINK_RGB_PRICE_SERVER_URL: rgbPriceServer || void 0,
|
|
2670
2835
|
LINK_RGB_REMOTE_NODE_PUBKEY: officialRgbPeer,
|
|
2671
2836
|
LINK_RGB_REMOTE_NODE_HOST: officialRgbPeerHost,
|
|
2672
2837
|
LINK_BITCOIND_RPCHOST: bitcoindRpcHost && bitcoindRpcPort ? `${bitcoindRpcHost}:${bitcoindRpcPort}` : void 0,
|
|
@@ -2900,13 +3065,16 @@ var require_getConfig = __commonJS({
|
|
|
2900
3065
|
}
|
|
2901
3066
|
combinedConfig.LINK_TOR_SOCKS_PORT = combinedConfig.LINK_TOR_SOCKS_PORT || 9050;
|
|
2902
3067
|
combinedConfig.LINK_TOR_CONTROL_PORT = combinedConfig.LINK_TOR_CONTROL_PORT || 9051;
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3068
|
+
const isExternalNodes = combinedConfig.LINK_EXTERNAL_NODES === "true" || combinedConfig.LINK_EXTERNAL_NODES === true;
|
|
3069
|
+
if (!isExternalNodes) {
|
|
3070
|
+
try {
|
|
3071
|
+
combinedConfig = await assignAvailablePorts(combinedConfig);
|
|
3072
|
+
} catch (portError) {
|
|
3073
|
+
console.warn(
|
|
3074
|
+
"Port assignment failed, using default ports:",
|
|
3075
|
+
portError.message
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
2910
3078
|
}
|
|
2911
3079
|
combinedConfig.LINK_GRPC_HOST = `localhost:${combinedConfig.LINK_LND_RPC_PORT}`;
|
|
2912
3080
|
combinedConfig.LINK_ENABLE_TOR = combinedConfig.LINK_ENABLE_TOR === "true" || combinedConfig.LINK_ENABLE_TOR === true;
|
|
@@ -5384,6 +5552,10 @@ var require_config2 = __commonJS({
|
|
|
5384
5552
|
}
|
|
5385
5553
|
try {
|
|
5386
5554
|
const config = getConfig2();
|
|
5555
|
+
const isExternalNodes = config.LINK_EXTERNAL_NODES === "true" || config.LINK_EXTERNAL_NODES === true;
|
|
5556
|
+
if (isExternalNodes) {
|
|
5557
|
+
return null;
|
|
5558
|
+
}
|
|
5387
5559
|
const torBinary = path2.join(config.LINK_BINARY_PATH || "", getBinaryName("tor"));
|
|
5388
5560
|
const output = execSync(`"${torBinary}" --hash-password "${TOR_CONTROL_PASSWORD}"`, {
|
|
5389
5561
|
encoding: "utf-8",
|
|
@@ -6108,7 +6280,8 @@ var require_client4 = __commonJS({
|
|
|
6108
6280
|
throw new Error("RGB configuration not available");
|
|
6109
6281
|
}
|
|
6110
6282
|
rgbClient = new RgbApiClient({
|
|
6111
|
-
baseUrl: `http://127.0.0.1:${config.LINK_RGB_LISTENING_PORT}
|
|
6283
|
+
// baseUrl: `http://127.0.0.1:${config.LINK_RGB_LISTENING_PORT}`,
|
|
6284
|
+
baseUrl: "http://35.221.95.26:9744"
|
|
6112
6285
|
});
|
|
6113
6286
|
}
|
|
6114
6287
|
return rgbClient;
|
|
@@ -7181,7 +7354,7 @@ var require_package = __commonJS({
|
|
|
7181
7354
|
"package.json"(exports2, module2) {
|
|
7182
7355
|
module2.exports = {
|
|
7183
7356
|
name: "lnlink-server",
|
|
7184
|
-
version: "1.1.
|
|
7357
|
+
version: "1.1.8",
|
|
7185
7358
|
private: false,
|
|
7186
7359
|
main: "dist/index.js",
|
|
7187
7360
|
files: [
|
|
@@ -7193,7 +7366,7 @@ var require_package = __commonJS({
|
|
|
7193
7366
|
build: "node build.js && node build.js --mode development --external all --entry electron",
|
|
7194
7367
|
"start:bin": "node scripts/start-bin.js",
|
|
7195
7368
|
"start:docker:dev": "dotenv -e .env.dev -- docker compose -f ./docker-compose.dev.yml up --build",
|
|
7196
|
-
"start:dev": 'dotenv -e .env.dev -- sh -c "prisma generate && (prisma migrate dev --name auto_update || prisma db push) &&
|
|
7369
|
+
"start:dev": 'dotenv -e .env.dev -- sh -c "prisma generate && (prisma migrate dev --name auto_update || prisma db push) && node ./app.js"',
|
|
7197
7370
|
"start:regtest": "docker compose --env-file ./.env.regtest -f ./docker-compose-lnlink.yml up --build",
|
|
7198
7371
|
"start:testnet": "docker compose --env-file ./.env.testnet -f ./docker-compose-lnlink.yml up --build",
|
|
7199
7372
|
"start:mainnet": "docker compose --env-file ./.env.mainnet -f ./docker-compose-lnlink.yml up --build",
|
|
@@ -7810,13 +7983,19 @@ var require_lndService = __commonJS({
|
|
|
7810
7983
|
}
|
|
7811
7984
|
if (state >= WALLET_STATE_CODE.RPC_ACTIVE && isMacaroonDecrypted && state !== WALLET_STATE_CODE.WAITING_TO_START) {
|
|
7812
7985
|
const lightningService = getLightningService();
|
|
7813
|
-
const
|
|
7814
|
-
getMainLnlinkConfig()
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7986
|
+
const promises = [
|
|
7987
|
+
getMainLnlinkConfig()
|
|
7988
|
+
];
|
|
7989
|
+
if (state >= WALLET_STATE_CODE.SERVER_ACTIVE) {
|
|
7990
|
+
promises.push(getCacheNodeInfo(true));
|
|
7991
|
+
promises.push(lightningService.walletBalance());
|
|
7992
|
+
promises.push(lightningService.listPeers({}));
|
|
7993
|
+
}
|
|
7994
|
+
const ret = await Promise.allSettled(promises);
|
|
7995
|
+
const configResult = ret[0];
|
|
7996
|
+
const infoResult = state >= WALLET_STATE_CODE.SERVER_ACTIVE ? ret[1] : { status: "rejected" };
|
|
7997
|
+
const balanceResult = state >= WALLET_STATE_CODE.SERVER_ACTIVE ? ret[2] : { status: "rejected" };
|
|
7998
|
+
const peersResult = state >= WALLET_STATE_CODE.SERVER_ACTIVE ? ret[3] : { status: "rejected" };
|
|
7820
7999
|
let settings = null;
|
|
7821
8000
|
if (configResult.status === "fulfilled") {
|
|
7822
8001
|
settings = configResult.value?.settings;
|
|
@@ -7835,9 +8014,11 @@ var require_lndService = __commonJS({
|
|
|
7835
8014
|
address: peer.address
|
|
7836
8015
|
};
|
|
7837
8016
|
});
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
8017
|
+
if (state >= WALLET_STATE_CODE.SERVER_ACTIVE) {
|
|
8018
|
+
logger2.info(
|
|
8019
|
+
`LND lndService combineNodeInfoAsync peer:${peers.map((item) => item.pub_key)}`
|
|
8020
|
+
);
|
|
8021
|
+
}
|
|
7841
8022
|
const errors = ret?.filter((p) => p.status === "rejected")?.map((p) => p.reason);
|
|
7842
8023
|
if (errors && errors.length > 0) {
|
|
7843
8024
|
logger2.error(
|
|
@@ -8579,7 +8760,11 @@ var require_api = __commonJS({
|
|
|
8579
8760
|
socket.setTimeout(TIMEOUT);
|
|
8580
8761
|
socket.once("connect", () => {
|
|
8581
8762
|
socket.destroy();
|
|
8582
|
-
resolve({
|
|
8763
|
+
resolve({
|
|
8764
|
+
host,
|
|
8765
|
+
port,
|
|
8766
|
+
reachable: true
|
|
8767
|
+
});
|
|
8583
8768
|
});
|
|
8584
8769
|
socket.once("timeout", () => {
|
|
8585
8770
|
socket.destroy();
|
|
@@ -8596,10 +8781,26 @@ var require_api = __commonJS({
|
|
|
8596
8781
|
__name(tryConnect2, "tryConnect");
|
|
8597
8782
|
const net = require("node:net");
|
|
8598
8783
|
const TOR_DIR_AUTHORITIES = [
|
|
8599
|
-
{
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8784
|
+
{
|
|
8785
|
+
host: "128.31.0.34",
|
|
8786
|
+
port: 9131,
|
|
8787
|
+
name: "moria1"
|
|
8788
|
+
},
|
|
8789
|
+
{
|
|
8790
|
+
host: "193.23.244.244",
|
|
8791
|
+
port: 443,
|
|
8792
|
+
name: "dannenberg"
|
|
8793
|
+
},
|
|
8794
|
+
{
|
|
8795
|
+
host: "199.58.81.140",
|
|
8796
|
+
port: 80,
|
|
8797
|
+
name: "Faravahar"
|
|
8798
|
+
},
|
|
8799
|
+
{
|
|
8800
|
+
host: "86.59.21.38",
|
|
8801
|
+
port: 443,
|
|
8802
|
+
name: "gabelmoo"
|
|
8803
|
+
}
|
|
8603
8804
|
];
|
|
8604
8805
|
const TIMEOUT = 5e3;
|
|
8605
8806
|
let reachable = false;
|
|
@@ -9470,10 +9671,20 @@ var require_tapdService = __commonJS({
|
|
|
9470
9671
|
const decodedInvoice = decode(payment_request);
|
|
9471
9672
|
const routingInfo = decodedInvoice.tags.find((tag) => tag.tagName === "routing_info");
|
|
9472
9673
|
if (routingInfo && routingInfo.data && routingInfo.data.length > 0) {
|
|
9473
|
-
const
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9674
|
+
const route_hints = routingInfo.data.map((hop) => {
|
|
9675
|
+
return {
|
|
9676
|
+
hop_hints: [
|
|
9677
|
+
{
|
|
9678
|
+
node_id: hop.pubkey,
|
|
9679
|
+
chan_id: BigInt(`0x${hop.short_channel_id}`).toString(),
|
|
9680
|
+
fee_base_msat: hop.fee_base_msat,
|
|
9681
|
+
fee_proportional_millionths: hop.fee_proportional_millionths,
|
|
9682
|
+
cltv_expiry_delta: hop.cltv_expiry_delta
|
|
9683
|
+
}
|
|
9684
|
+
]
|
|
9685
|
+
};
|
|
9686
|
+
});
|
|
9687
|
+
paymentRequest.route_hints = route_hints;
|
|
9477
9688
|
}
|
|
9478
9689
|
const sendParams = {
|
|
9479
9690
|
asset_amount,
|
|
@@ -9682,7 +9893,7 @@ var require_tapdService = __commonJS({
|
|
|
9682
9893
|
if (!retIsConnectPeer) {
|
|
9683
9894
|
throw new Error("Peer not connected");
|
|
9684
9895
|
}
|
|
9685
|
-
const
|
|
9896
|
+
const createInvoiceArgs = {
|
|
9686
9897
|
asset_amount,
|
|
9687
9898
|
asset_id: Buffer2.from(asset_id, "hex"),
|
|
9688
9899
|
peer_pubkey: Buffer2.from(remotePubkey, "hex"),
|
|
@@ -9691,7 +9902,8 @@ var require_tapdService = __commonJS({
|
|
|
9691
9902
|
expiry,
|
|
9692
9903
|
description_hash: description_hash ? Buffer2.from(description_hash, "hex") : void 0
|
|
9693
9904
|
}
|
|
9694
|
-
}
|
|
9905
|
+
};
|
|
9906
|
+
const invoice = await tapChannelService.addInvoice(createInvoiceArgs);
|
|
9695
9907
|
const payment_req = invoice?.invoice_result?.payment_request;
|
|
9696
9908
|
if (payment_req) {
|
|
9697
9909
|
await sleep(500);
|
|
@@ -9845,7 +10057,7 @@ var require_constants2 = __commonJS({
|
|
|
9845
10057
|
SOCIAL_ID_MISMATCH: "Social id don't match",
|
|
9846
10058
|
METHOD_NOT_SUPPORTED: "Method not supported"
|
|
9847
10059
|
};
|
|
9848
|
-
var PRIVILEGED_METHODS = ["make_invoice", "pay_invoice"];
|
|
10060
|
+
var PRIVILEGED_METHODS = ["make_invoice", "pay_invoice", "create_hodl_invoice"];
|
|
9849
10061
|
var FLASH_ACCOUNT_METHODS = [
|
|
9850
10062
|
"make_invoice",
|
|
9851
10063
|
"pay_invoice",
|
|
@@ -11346,8 +11558,9 @@ var require_nwcProxy = __commonJS({
|
|
|
11346
11558
|
}
|
|
11347
11559
|
} else {
|
|
11348
11560
|
const filterChannelList = channelList.filter((item) => {
|
|
11349
|
-
const
|
|
11350
|
-
|
|
11561
|
+
const asset_genesis = item?.custom_channel_data?.assets?.[0]?.asset_utxo?.asset_genesis || item?.custom_channel_data?.funding_assets?.[0]?.asset_genesis;
|
|
11562
|
+
const custom_channel_asset_id = asset_genesis?.asset_id;
|
|
11563
|
+
return item.commitment_type.includes("TAPROOT") && item.active === true && custom_channel_asset_id === assetId;
|
|
11351
11564
|
});
|
|
11352
11565
|
if (filterChannelList.length > 0) {
|
|
11353
11566
|
return filterChannelList.sort((a, b) => {
|
|
@@ -11480,9 +11693,15 @@ var require_nwcProxy = __commonJS({
|
|
|
11480
11693
|
}
|
|
11481
11694
|
const create_at = Math.floor(Date.now() / 1e3);
|
|
11482
11695
|
const expire_at = create_at + (expiry ?? 5 * 60);
|
|
11696
|
+
const chan_id = await getBestOutgoingChainId(
|
|
11697
|
+
asset_id
|
|
11698
|
+
).catch(() => {
|
|
11699
|
+
return false;
|
|
11700
|
+
});
|
|
11483
11701
|
const invoice = await addInvoice({
|
|
11484
11702
|
asset_amount: amount,
|
|
11485
11703
|
asset_id,
|
|
11704
|
+
chan_id,
|
|
11486
11705
|
description,
|
|
11487
11706
|
description_hash,
|
|
11488
11707
|
expiry,
|
|
@@ -11619,7 +11838,9 @@ var require_nwcProxy = __commonJS({
|
|
|
11619
11838
|
result: {
|
|
11620
11839
|
preimage: payment?.payment_result?.payment_preimage,
|
|
11621
11840
|
payment_hash: payment?.payment_result?.payment_hash,
|
|
11622
|
-
asset_id: lnlinkUser.asset_id
|
|
11841
|
+
asset_id: lnlinkUser.asset_id,
|
|
11842
|
+
status: payment?.payment_result?.status,
|
|
11843
|
+
failure_reason: payment?.payment_result?.failure_reason
|
|
11623
11844
|
}
|
|
11624
11845
|
});
|
|
11625
11846
|
}
|
|
@@ -11795,7 +12016,7 @@ var require_nwcProxy = __commonJS({
|
|
|
11795
12016
|
user_npub: lnlinkUser.npub,
|
|
11796
12017
|
node_type: NODE_TYPE.LITD,
|
|
11797
12018
|
transaction_kind: TRANSACTION_KIND.LIGHTNING,
|
|
11798
|
-
asset_id
|
|
12019
|
+
asset_id: lnlinkUser?.asset_id || asset_id
|
|
11799
12020
|
});
|
|
11800
12021
|
total = allTotal;
|
|
11801
12022
|
return allList.map((item) => ({
|
|
@@ -12072,7 +12293,7 @@ var require_info = __commonJS({
|
|
|
12072
12293
|
] = await Promise.allSettled([
|
|
12073
12294
|
rgbClient.node.getNodeInfo(),
|
|
12074
12295
|
rgbClient.onchain.getBtcBalance({
|
|
12075
|
-
skip_sync:
|
|
12296
|
+
skip_sync: false
|
|
12076
12297
|
// Skip sync for faster response
|
|
12077
12298
|
}),
|
|
12078
12299
|
rgbClient.lightning.listPeers({})
|
|
@@ -12214,6 +12435,7 @@ var require_lightning = __commonJS({
|
|
|
12214
12435
|
push_msat,
|
|
12215
12436
|
asset_amount,
|
|
12216
12437
|
asset_id,
|
|
12438
|
+
push_asset_amount = 0,
|
|
12217
12439
|
isPublic = true,
|
|
12218
12440
|
with_anchors = true,
|
|
12219
12441
|
fee_base_msat = 1e3,
|
|
@@ -12226,12 +12448,11 @@ var require_lightning = __commonJS({
|
|
|
12226
12448
|
host,
|
|
12227
12449
|
capacity_sat,
|
|
12228
12450
|
push_msat,
|
|
12229
|
-
asset_amount,
|
|
12230
|
-
asset_id,
|
|
12231
12451
|
public: isPublic,
|
|
12232
12452
|
with_anchors,
|
|
12233
12453
|
fee_base_msat: Number(fee_base_msat),
|
|
12234
|
-
fee_proportional_millionths
|
|
12454
|
+
fee_proportional_millionths,
|
|
12455
|
+
...asset_id ? { asset_id, asset_amount, push_asset_amount } : {}
|
|
12235
12456
|
};
|
|
12236
12457
|
const { is_connected, peer } = await isConnectPeer({
|
|
12237
12458
|
pubkey
|
|
@@ -12942,6 +13163,190 @@ var require_rgb = __commonJS({
|
|
|
12942
13163
|
}
|
|
12943
13164
|
});
|
|
12944
13165
|
|
|
13166
|
+
// business/service/rgb/exchange.js
|
|
13167
|
+
var require_exchange = __commonJS({
|
|
13168
|
+
"business/service/rgb/exchange.js"(exports2, module2) {
|
|
13169
|
+
var { checkObjectArgs } = require_common();
|
|
13170
|
+
var { getConfigValue } = require_getConfig();
|
|
13171
|
+
var {
|
|
13172
|
+
createExchangeOrder,
|
|
13173
|
+
getExchangeOrderByPaymentHash,
|
|
13174
|
+
getExchangeOrderById,
|
|
13175
|
+
getExchangeOrders,
|
|
13176
|
+
updateExchangeOrder
|
|
13177
|
+
} = require_dbService();
|
|
13178
|
+
var Logger = require_linkLogger();
|
|
13179
|
+
var getRgbClient = require_client4();
|
|
13180
|
+
var { decodeLnInvoice, listChannels } = require_lightning();
|
|
13181
|
+
var EXCHANGE_ORDER_STATUS = {
|
|
13182
|
+
CREATED: "created",
|
|
13183
|
+
RGB_HODL_ISSUED: "rgb_hodl_issued",
|
|
13184
|
+
RGB_PAID: "rgb_paid",
|
|
13185
|
+
BTC_SENDING: "btc_sending",
|
|
13186
|
+
BTC_SENT: "btc_sent",
|
|
13187
|
+
COMPLETED: "completed",
|
|
13188
|
+
FAILED: "failed"
|
|
13189
|
+
};
|
|
13190
|
+
var HODL_BUFFER_SEC = 7200;
|
|
13191
|
+
async function createHodlInvoice({
|
|
13192
|
+
btc_invoice,
|
|
13193
|
+
asset_id,
|
|
13194
|
+
asset_amount
|
|
13195
|
+
}) {
|
|
13196
|
+
const logger2 = new Logger("rgb-exchange");
|
|
13197
|
+
checkObjectArgs({
|
|
13198
|
+
btc_invoice,
|
|
13199
|
+
asset_id,
|
|
13200
|
+
asset_amount
|
|
13201
|
+
}, ["btc_invoice", "asset_id", "asset_amount"]);
|
|
13202
|
+
const parsedAssetAmount = Number(asset_amount);
|
|
13203
|
+
if (!Number.isFinite(parsedAssetAmount) || parsedAssetAmount <= 0 || !Number.isInteger(parsedAssetAmount)) {
|
|
13204
|
+
throw new Error(`asset_amount must be a positive integer, got: ${asset_amount}`);
|
|
13205
|
+
}
|
|
13206
|
+
const decoded = await decodeLnInvoice({ invoice: btc_invoice });
|
|
13207
|
+
const {
|
|
13208
|
+
payment_hash,
|
|
13209
|
+
amt_msat,
|
|
13210
|
+
timestamp,
|
|
13211
|
+
expiry_sec: btc_expiry_sec
|
|
13212
|
+
} = decoded;
|
|
13213
|
+
if (!payment_hash) {
|
|
13214
|
+
throw new Error("Failed to extract payment_hash from BTC invoice");
|
|
13215
|
+
}
|
|
13216
|
+
if (!amt_msat) {
|
|
13217
|
+
throw new Error("BTC invoice has no amount");
|
|
13218
|
+
}
|
|
13219
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
13220
|
+
const btcExpireAt = Number(timestamp) + Number(btc_expiry_sec);
|
|
13221
|
+
const remaining = btcExpireAt - now;
|
|
13222
|
+
if (remaining <= HODL_BUFFER_SEC) {
|
|
13223
|
+
throw new Error(`BTC invoice expires too soon (remaining: ${remaining}s, required > ${HODL_BUFFER_SEC}s)`);
|
|
13224
|
+
}
|
|
13225
|
+
const hodl_expiry_sec = remaining - HODL_BUFFER_SEC;
|
|
13226
|
+
const { channels = [] } = await listChannels();
|
|
13227
|
+
const btcOutbound = channels.filter((ch) => !ch.asset_id && (ch.is_usable !== false && ch.ready !== false)).reduce((sum, ch) => {
|
|
13228
|
+
const balance = Number(ch.outbound_balance_msat || ch.local_balance_msat || 0);
|
|
13229
|
+
return sum + balance;
|
|
13230
|
+
}, 0);
|
|
13231
|
+
if (btcOutbound === 0) {
|
|
13232
|
+
logger2.warn(`BTC outbound balance is 0 \u2014 verify channel field names. Sample channel: ${JSON.stringify(channels[0] || {})}`);
|
|
13233
|
+
}
|
|
13234
|
+
if (btcOutbound < Number(amt_msat)) {
|
|
13235
|
+
throw new Error(`Insufficient BTC outbound liquidity (available: ${btcOutbound} msat, required: ${amt_msat} msat)`);
|
|
13236
|
+
}
|
|
13237
|
+
const existing = await getExchangeOrderByPaymentHash(payment_hash);
|
|
13238
|
+
if (existing) {
|
|
13239
|
+
throw new Error(`Exchange order already exists for payment_hash: ${payment_hash}`);
|
|
13240
|
+
}
|
|
13241
|
+
const RGB_MIN_AMT_MSAT = 3 * 1e3 * 1e3;
|
|
13242
|
+
const rgbClient = getRgbClient();
|
|
13243
|
+
const invoiceResult = await rgbClient.lightning.createHodlInvoice({
|
|
13244
|
+
payment_hash,
|
|
13245
|
+
amt_msat: RGB_MIN_AMT_MSAT,
|
|
13246
|
+
expiry_sec: hodl_expiry_sec,
|
|
13247
|
+
asset_id,
|
|
13248
|
+
asset_amount: parsedAssetAmount
|
|
13249
|
+
});
|
|
13250
|
+
const htlc_expiry_at = now + hodl_expiry_sec;
|
|
13251
|
+
const order = await createExchangeOrder({
|
|
13252
|
+
payment_hash,
|
|
13253
|
+
btc_invoice,
|
|
13254
|
+
btc_amount: String(amt_msat),
|
|
13255
|
+
rgb_invoice: invoiceResult.invoice,
|
|
13256
|
+
asset_id,
|
|
13257
|
+
asset_amount: String(asset_amount),
|
|
13258
|
+
status: EXCHANGE_ORDER_STATUS.RGB_HODL_ISSUED,
|
|
13259
|
+
htlc_expiry_at,
|
|
13260
|
+
created_at: now,
|
|
13261
|
+
updated_at: now
|
|
13262
|
+
});
|
|
13263
|
+
logger2.info(`Exchange order created: id=${order.id}, payment_hash=${payment_hash}`);
|
|
13264
|
+
return {
|
|
13265
|
+
invoice: invoiceResult.invoice,
|
|
13266
|
+
payment_hash,
|
|
13267
|
+
expiry_sec: hodl_expiry_sec,
|
|
13268
|
+
exchange_order_id: order.id,
|
|
13269
|
+
btc_amount: String(amt_msat)
|
|
13270
|
+
};
|
|
13271
|
+
}
|
|
13272
|
+
__name(createHodlInvoice, "createHodlInvoice");
|
|
13273
|
+
var BTC_ASSET_ID = "0000000000000000000000000000000000000000000000000000000000000000";
|
|
13274
|
+
async function getExchangeRate({ asset_id }) {
|
|
13275
|
+
const logger2 = new Logger("rgb-exchange");
|
|
13276
|
+
checkObjectArgs({ asset_id }, ["asset_id"]);
|
|
13277
|
+
const priceServerUrl = getConfigValue("LINK_RGB_PRICE_SERVER_URL");
|
|
13278
|
+
if (!priceServerUrl) {
|
|
13279
|
+
throw new Error("Price server URL not configured (LINK_RGB_PRICE_SERVER_URL)");
|
|
13280
|
+
}
|
|
13281
|
+
if (!priceServerUrl.startsWith("http://") && !priceServerUrl.startsWith("https://")) {
|
|
13282
|
+
throw new Error(`Invalid price server URL scheme: ${priceServerUrl}`);
|
|
13283
|
+
}
|
|
13284
|
+
const baseUrl = priceServerUrl.replace(/\/$/, "");
|
|
13285
|
+
const url = `${baseUrl}/price/getOne?transaction_type=0&subjectAssetId=${encodeURIComponent(asset_id)}&paymentAssetId=${BTC_ASSET_ID}`;
|
|
13286
|
+
const res = await fetch(url);
|
|
13287
|
+
if (!res.ok) {
|
|
13288
|
+
throw new Error(`Price oracle error: ${res.status} ${res.statusText}`);
|
|
13289
|
+
}
|
|
13290
|
+
const body = await res.json();
|
|
13291
|
+
if (!body.ok || !body.ok.assetRates) {
|
|
13292
|
+
throw new Error(`Price oracle returned error: ${JSON.stringify(body)}`);
|
|
13293
|
+
}
|
|
13294
|
+
const { assetRates } = body.ok;
|
|
13295
|
+
logger2.info(`Exchange rate fetched for asset ${asset_id}: coefficient=${assetRates.subjectAssetRate?.coefficient}, scale=${assetRates.subjectAssetRate?.scale}`);
|
|
13296
|
+
return { assetRates };
|
|
13297
|
+
}
|
|
13298
|
+
__name(getExchangeRate, "getExchangeRate");
|
|
13299
|
+
async function listExchangeOrders({
|
|
13300
|
+
status,
|
|
13301
|
+
page = 1,
|
|
13302
|
+
page_size = 20
|
|
13303
|
+
} = {}) {
|
|
13304
|
+
const validStatuses = Object.values(EXCHANGE_ORDER_STATUS);
|
|
13305
|
+
if (status && !validStatuses.includes(status)) {
|
|
13306
|
+
throw new Error(`Invalid status: ${status}. Valid values: ${validStatuses.join(", ")}`);
|
|
13307
|
+
}
|
|
13308
|
+
const safePage = Math.max(1, parseInt(page) || 1);
|
|
13309
|
+
const safePageSize = Math.min(100, Math.max(1, parseInt(page_size) || 20));
|
|
13310
|
+
const { list, total } = await getExchangeOrders({
|
|
13311
|
+
status,
|
|
13312
|
+
page: safePage,
|
|
13313
|
+
page_size: safePageSize
|
|
13314
|
+
});
|
|
13315
|
+
return {
|
|
13316
|
+
orders: list.map((order) => ({
|
|
13317
|
+
id: order.id,
|
|
13318
|
+
payment_hash: order.payment_hash,
|
|
13319
|
+
btc_amount: order.btc_amount,
|
|
13320
|
+
asset_id: order.asset_id,
|
|
13321
|
+
asset_amount: order.asset_amount,
|
|
13322
|
+
status: order.status,
|
|
13323
|
+
error_message: order.error_message,
|
|
13324
|
+
created_at: order.created_at,
|
|
13325
|
+
updated_at: order.updated_at
|
|
13326
|
+
})),
|
|
13327
|
+
total
|
|
13328
|
+
};
|
|
13329
|
+
}
|
|
13330
|
+
__name(listExchangeOrders, "listExchangeOrders");
|
|
13331
|
+
async function getExchangeOrder({ order_id }) {
|
|
13332
|
+
checkObjectArgs({ order_id }, ["order_id"]);
|
|
13333
|
+
const order = await getExchangeOrderById(Number(order_id));
|
|
13334
|
+
if (!order) {
|
|
13335
|
+
throw new Error(`Exchange order not found: ${order_id}`);
|
|
13336
|
+
}
|
|
13337
|
+
return order;
|
|
13338
|
+
}
|
|
13339
|
+
__name(getExchangeOrder, "getExchangeOrder");
|
|
13340
|
+
module2.exports = {
|
|
13341
|
+
EXCHANGE_ORDER_STATUS,
|
|
13342
|
+
createHodlInvoice,
|
|
13343
|
+
getExchangeRate,
|
|
13344
|
+
listExchangeOrders,
|
|
13345
|
+
getExchangeOrder
|
|
13346
|
+
};
|
|
13347
|
+
}
|
|
13348
|
+
});
|
|
13349
|
+
|
|
12945
13350
|
// business/service/proxy/rgbProxy.js
|
|
12946
13351
|
var require_rgbProxy = __commonJS({
|
|
12947
13352
|
"business/service/proxy/rgbProxy.js"(exports2, module2) {
|
|
@@ -12976,6 +13381,12 @@ var require_rgbProxy = __commonJS({
|
|
|
12976
13381
|
restoreNode,
|
|
12977
13382
|
getRGBAssetsList
|
|
12978
13383
|
} = require_rgb();
|
|
13384
|
+
var {
|
|
13385
|
+
createHodlInvoice,
|
|
13386
|
+
getExchangeRate,
|
|
13387
|
+
listExchangeOrders,
|
|
13388
|
+
getExchangeOrder
|
|
13389
|
+
} = require_exchange();
|
|
12979
13390
|
function rgbProxy() {
|
|
12980
13391
|
return {
|
|
12981
13392
|
// ---node manager
|
|
@@ -13165,6 +13576,35 @@ var require_rgbProxy = __commonJS({
|
|
|
13165
13576
|
readonly: true
|
|
13166
13577
|
};
|
|
13167
13578
|
}, "decode_ln_invoice"),
|
|
13579
|
+
// ---exchange
|
|
13580
|
+
create_hodl_invoice: /* @__PURE__ */ __name(async () => {
|
|
13581
|
+
return {
|
|
13582
|
+
method: createHodlInvoice,
|
|
13583
|
+
argNames: ["btc_invoice", "asset_id", "asset_amount"],
|
|
13584
|
+
readonly: false
|
|
13585
|
+
};
|
|
13586
|
+
}, "create_hodl_invoice"),
|
|
13587
|
+
get_exchange_rate: /* @__PURE__ */ __name(async () => {
|
|
13588
|
+
return {
|
|
13589
|
+
method: getExchangeRate,
|
|
13590
|
+
argNames: ["asset_id"],
|
|
13591
|
+
readonly: true
|
|
13592
|
+
};
|
|
13593
|
+
}, "get_exchange_rate"),
|
|
13594
|
+
list_exchange_orders: /* @__PURE__ */ __name(async () => {
|
|
13595
|
+
return {
|
|
13596
|
+
method: listExchangeOrders,
|
|
13597
|
+
argNames: ["status", "page", "page_size"],
|
|
13598
|
+
readonly: true
|
|
13599
|
+
};
|
|
13600
|
+
}, "list_exchange_orders"),
|
|
13601
|
+
get_exchange_order: /* @__PURE__ */ __name(async () => {
|
|
13602
|
+
return {
|
|
13603
|
+
method: getExchangeOrder,
|
|
13604
|
+
argNames: ["order_id"],
|
|
13605
|
+
readonly: true
|
|
13606
|
+
};
|
|
13607
|
+
}, "get_exchange_order"),
|
|
13168
13608
|
backup_node: /* @__PURE__ */ __name(async () => {
|
|
13169
13609
|
return {
|
|
13170
13610
|
method: backupNode,
|
|
@@ -14844,8 +15284,8 @@ var require_mempool = __commonJS({
|
|
|
14844
15284
|
const { LINK_NETWORK } = getConfig2();
|
|
14845
15285
|
if ((LINK_NETWORK || "").toLowerCase() === "regtest") {
|
|
14846
15286
|
return {
|
|
14847
|
-
apiBase: "http://34.84.
|
|
14848
|
-
pageBase: "http://34.84.
|
|
15287
|
+
apiBase: "http://34.84.69.164:8889/api",
|
|
15288
|
+
pageBase: "http://34.84.69.164:8889/zh"
|
|
14849
15289
|
};
|
|
14850
15290
|
}
|
|
14851
15291
|
return {
|
|
@@ -15740,6 +16180,321 @@ var require_pollBtcTransfers2 = __commonJS({
|
|
|
15740
16180
|
}
|
|
15741
16181
|
});
|
|
15742
16182
|
|
|
16183
|
+
// business/job/rgb/pollExchangeOrders.js
|
|
16184
|
+
var require_pollExchangeOrders = __commonJS({
|
|
16185
|
+
"business/job/rgb/pollExchangeOrders.js"(exports2, module2) {
|
|
16186
|
+
var {
|
|
16187
|
+
getExchangeOrdersByStatusIn,
|
|
16188
|
+
getExchangeOrderById,
|
|
16189
|
+
updateExchangeOrderWithExpectedStatus
|
|
16190
|
+
} = require_dbService();
|
|
16191
|
+
var getRgbClient = require_client4();
|
|
16192
|
+
var { EXCHANGE_ORDER_STATUS } = require_exchange();
|
|
16193
|
+
var { listPayments, listChannels } = require_lightning();
|
|
16194
|
+
var Logger = require_linkLogger();
|
|
16195
|
+
var POLL_STALE_MS = 6e4;
|
|
16196
|
+
var pollingStartedAt = 0;
|
|
16197
|
+
async function pollExchangeOrders() {
|
|
16198
|
+
const now = Date.now();
|
|
16199
|
+
if (pollingStartedAt > 0) {
|
|
16200
|
+
if (now - pollingStartedAt < POLL_STALE_MS) return;
|
|
16201
|
+
const logger2 = new Logger("poll-exchange-orders");
|
|
16202
|
+
logger2.warn(`Previous poll stuck for ${now - pollingStartedAt}ms, forcing re-entry`);
|
|
16203
|
+
}
|
|
16204
|
+
pollingStartedAt = now;
|
|
16205
|
+
try {
|
|
16206
|
+
const activeOrders = await getExchangeOrdersByStatusIn([
|
|
16207
|
+
EXCHANGE_ORDER_STATUS.RGB_HODL_ISSUED,
|
|
16208
|
+
EXCHANGE_ORDER_STATUS.RGB_PAID,
|
|
16209
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16210
|
+
EXCHANGE_ORDER_STATUS.BTC_SENT
|
|
16211
|
+
]);
|
|
16212
|
+
if (!activeOrders || activeOrders.length === 0) {
|
|
16213
|
+
return;
|
|
16214
|
+
}
|
|
16215
|
+
const logger2 = new Logger("poll-exchange-orders");
|
|
16216
|
+
logger2.info(`Polling ${activeOrders.length} active exchange orders`);
|
|
16217
|
+
let payments = [];
|
|
16218
|
+
try {
|
|
16219
|
+
const paymentsResult = await listPayments();
|
|
16220
|
+
payments = paymentsResult && paymentsResult.payments ? paymentsResult.payments : [];
|
|
16221
|
+
} catch (error) {
|
|
16222
|
+
logger2.warn(`Failed to fetch listPayments, detection skipped: ${error.message}`);
|
|
16223
|
+
}
|
|
16224
|
+
const rgbClient = getRgbClient();
|
|
16225
|
+
for (const order of activeOrders) {
|
|
16226
|
+
try {
|
|
16227
|
+
await processOrder(order, payments, rgbClient, logger2);
|
|
16228
|
+
} catch (error) {
|
|
16229
|
+
logger2.error(`Error processing exchange order ${order.id}: ${error.message}`);
|
|
16230
|
+
}
|
|
16231
|
+
}
|
|
16232
|
+
} finally {
|
|
16233
|
+
pollingStartedAt = 0;
|
|
16234
|
+
}
|
|
16235
|
+
}
|
|
16236
|
+
__name(pollExchangeOrders, "pollExchangeOrders");
|
|
16237
|
+
var MAX_BTC_RETRIES = 10;
|
|
16238
|
+
async function processOrder(order, payments, rgbClient, logger2) {
|
|
16239
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
16240
|
+
switch (order.status) {
|
|
16241
|
+
case EXCHANGE_ORDER_STATUS.RGB_HODL_ISSUED: {
|
|
16242
|
+
if (order.htlc_expiry_at && now > order.htlc_expiry_at) {
|
|
16243
|
+
const updated = await updateExchangeOrderWithExpectedStatus(
|
|
16244
|
+
order.id,
|
|
16245
|
+
EXCHANGE_ORDER_STATUS.RGB_HODL_ISSUED,
|
|
16246
|
+
{ status: EXCHANGE_ORDER_STATUS.FAILED, error_message: "HODL invoice expired, A never paid" }
|
|
16247
|
+
);
|
|
16248
|
+
if (updated) logger2.info(`Order ${order.id}: expired in rgb_hodl_issued, marked failed`);
|
|
16249
|
+
break;
|
|
16250
|
+
}
|
|
16251
|
+
const hodlPending = payments.find(
|
|
16252
|
+
(p) => p.payment_hash === order.payment_hash && p.inbound === true && p.status === "Pending" && p.asset_id
|
|
16253
|
+
);
|
|
16254
|
+
if (hodlPending) {
|
|
16255
|
+
const updated = await updateExchangeOrderWithExpectedStatus(
|
|
16256
|
+
order.id,
|
|
16257
|
+
EXCHANGE_ORDER_STATUS.RGB_HODL_ISSUED,
|
|
16258
|
+
{ status: EXCHANGE_ORDER_STATUS.RGB_PAID, error_message: null }
|
|
16259
|
+
);
|
|
16260
|
+
if (updated) {
|
|
16261
|
+
logger2.info(`Order ${order.id}: RGB HODL payment received (Pending), updated to rgb_paid`);
|
|
16262
|
+
const freshOrder = await getExchangeOrderById(order.id);
|
|
16263
|
+
if (freshOrder) await sendBtcPayment(freshOrder, payments, rgbClient, logger2);
|
|
16264
|
+
} else {
|
|
16265
|
+
logger2.warn(`Order ${order.id}: optimistic lock failed on rgb_hodl_issued -> rgb_paid`);
|
|
16266
|
+
}
|
|
16267
|
+
}
|
|
16268
|
+
break;
|
|
16269
|
+
}
|
|
16270
|
+
case EXCHANGE_ORDER_STATUS.RGB_PAID:
|
|
16271
|
+
case EXCHANGE_ORDER_STATUS.BTC_SENDING: {
|
|
16272
|
+
if (order.status === EXCHANGE_ORDER_STATUS.BTC_SENDING) {
|
|
16273
|
+
const alreadySent = payments.find(
|
|
16274
|
+
(p) => p.payment_hash === order.payment_hash && p.inbound === false && p.status === "Succeeded"
|
|
16275
|
+
);
|
|
16276
|
+
if (alreadySent) {
|
|
16277
|
+
const preimage = alreadySent.preimage || null;
|
|
16278
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16279
|
+
order.id,
|
|
16280
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16281
|
+
{
|
|
16282
|
+
status: EXCHANGE_ORDER_STATUS.BTC_SENT,
|
|
16283
|
+
preimage,
|
|
16284
|
+
btc_retry_count: 0,
|
|
16285
|
+
error_message: null
|
|
16286
|
+
}
|
|
16287
|
+
);
|
|
16288
|
+
logger2.info(`Order ${order.id}: BTC payment already succeeded (crash recovery), advanced to btc_sent`);
|
|
16289
|
+
break;
|
|
16290
|
+
}
|
|
16291
|
+
}
|
|
16292
|
+
await sendBtcPayment(order, payments, rgbClient, logger2);
|
|
16293
|
+
break;
|
|
16294
|
+
}
|
|
16295
|
+
case EXCHANGE_ORDER_STATUS.BTC_SENT: {
|
|
16296
|
+
const btcSucceeded = payments.find(
|
|
16297
|
+
(p) => p.payment_hash === order.payment_hash && p.inbound === false && p.status === "Succeeded"
|
|
16298
|
+
);
|
|
16299
|
+
if (!btcSucceeded) {
|
|
16300
|
+
const btcFailed = payments.find(
|
|
16301
|
+
(p) => p.payment_hash === order.payment_hash && p.inbound === false && p.status === "Failed"
|
|
16302
|
+
);
|
|
16303
|
+
if (btcFailed) {
|
|
16304
|
+
const updated = await updateExchangeOrderWithExpectedStatus(
|
|
16305
|
+
order.id,
|
|
16306
|
+
EXCHANGE_ORDER_STATUS.BTC_SENT,
|
|
16307
|
+
{
|
|
16308
|
+
status: EXCHANGE_ORDER_STATUS.RGB_PAID,
|
|
16309
|
+
btc_retry_count: (order.btc_retry_count || 0) + 1,
|
|
16310
|
+
error_message: "BTC payment failed asynchronously, will retry"
|
|
16311
|
+
}
|
|
16312
|
+
);
|
|
16313
|
+
if (updated) logger2.warn(`Order ${order.id}: BTC payment failed async (retry ${(order.btc_retry_count || 0) + 1}/${MAX_BTC_RETRIES}), reverting to rgb_paid`);
|
|
16314
|
+
break;
|
|
16315
|
+
}
|
|
16316
|
+
}
|
|
16317
|
+
const hodlSucceeded = payments.find(
|
|
16318
|
+
(p) => p.payment_hash === order.payment_hash && p.inbound === true && p.status === "Succeeded" && p.asset_id
|
|
16319
|
+
);
|
|
16320
|
+
if (hodlSucceeded) {
|
|
16321
|
+
const updated = await updateExchangeOrderWithExpectedStatus(
|
|
16322
|
+
order.id,
|
|
16323
|
+
EXCHANGE_ORDER_STATUS.BTC_SENT,
|
|
16324
|
+
{
|
|
16325
|
+
status: EXCHANGE_ORDER_STATUS.COMPLETED,
|
|
16326
|
+
btc_retry_count: 0,
|
|
16327
|
+
error_message: null
|
|
16328
|
+
}
|
|
16329
|
+
);
|
|
16330
|
+
if (updated) logger2.info(`Order ${order.id}: RGB auto-claimed (Succeeded), marked completed`);
|
|
16331
|
+
} else {
|
|
16332
|
+
if (order.htlc_expiry_at && now > order.htlc_expiry_at) {
|
|
16333
|
+
const updated = await updateExchangeOrderWithExpectedStatus(
|
|
16334
|
+
order.id,
|
|
16335
|
+
EXCHANGE_ORDER_STATUS.BTC_SENT,
|
|
16336
|
+
{ status: EXCHANGE_ORDER_STATUS.FAILED, error_message: "HTLC expired: BTC sent but RGB auto-claim never fired (node event missed)" }
|
|
16337
|
+
);
|
|
16338
|
+
if (updated) logger2.error(`[LOSS] Order ${order.id}: HTLC expired in btc_sent, RGB not claimed. payment_hash=${order.payment_hash}`);
|
|
16339
|
+
} else if (order.htlc_expiry_at && now > order.htlc_expiry_at - 600) {
|
|
16340
|
+
logger2.error(`[ALERT] Order ${order.id} approaching HTLC expiry. payment_hash=${order.payment_hash}, preimage=${order.preimage}, htlc_expiry_at=${order.htlc_expiry_at}`);
|
|
16341
|
+
}
|
|
16342
|
+
}
|
|
16343
|
+
break;
|
|
16344
|
+
}
|
|
16345
|
+
}
|
|
16346
|
+
}
|
|
16347
|
+
__name(processOrder, "processOrder");
|
|
16348
|
+
async function sendBtcPayment(order, payments, rgbClient, logger2) {
|
|
16349
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
16350
|
+
if (order.htlc_expiry_at && now > order.htlc_expiry_at - 300) {
|
|
16351
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16352
|
+
order.id,
|
|
16353
|
+
order.status,
|
|
16354
|
+
{ status: EXCHANGE_ORDER_STATUS.FAILED, error_message: "HTLC expiry too close, aborting BTC payment" }
|
|
16355
|
+
);
|
|
16356
|
+
logger2.error(`Order ${order.id}: HTLC expiry imminent (${order.htlc_expiry_at - now}s left), marking failed`);
|
|
16357
|
+
return;
|
|
16358
|
+
}
|
|
16359
|
+
const retries = order.btc_retry_count || 0;
|
|
16360
|
+
if (retries >= MAX_BTC_RETRIES) {
|
|
16361
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16362
|
+
order.id,
|
|
16363
|
+
order.status,
|
|
16364
|
+
{ status: EXCHANGE_ORDER_STATUS.FAILED, error_message: `BTC payment failed after ${MAX_BTC_RETRIES} retries` }
|
|
16365
|
+
);
|
|
16366
|
+
logger2.error(`Order ${order.id}: exceeded max BTC retries (${MAX_BTC_RETRIES})`);
|
|
16367
|
+
return;
|
|
16368
|
+
}
|
|
16369
|
+
if (!order.btc_invoice) {
|
|
16370
|
+
await updateExchangeOrderWithExpectedStatus(order.id, order.status, { status: EXCHANGE_ORDER_STATUS.FAILED, error_message: "Missing btc_invoice" });
|
|
16371
|
+
logger2.error(`Order ${order.id}: btc_invoice is null/empty, marking failed`);
|
|
16372
|
+
return;
|
|
16373
|
+
}
|
|
16374
|
+
try {
|
|
16375
|
+
const { channels = [] } = await listChannels();
|
|
16376
|
+
const btcOutbound = channels.filter((ch) => !ch.asset_id && (ch.is_usable !== false && ch.ready !== false)).reduce((sum, ch) => sum + Number(ch.outbound_balance_msat || ch.local_balance_msat || 0), 0);
|
|
16377
|
+
const requiredMsat = Number(order.btc_amount);
|
|
16378
|
+
if (!Number.isFinite(requiredMsat) || requiredMsat <= 0) {
|
|
16379
|
+
await updateExchangeOrderWithExpectedStatus(order.id, order.status, { status: EXCHANGE_ORDER_STATUS.FAILED, error_message: `Invalid btc_amount: ${order.btc_amount}` });
|
|
16380
|
+
logger2.error(`Order ${order.id}: invalid btc_amount "${order.btc_amount}", marking failed`);
|
|
16381
|
+
return;
|
|
16382
|
+
}
|
|
16383
|
+
if (btcOutbound < requiredMsat) {
|
|
16384
|
+
logger2.warn(`Order ${order.id}: insufficient BTC outbound (available: ${btcOutbound}, required: ${requiredMsat}), skipping this tick`);
|
|
16385
|
+
return;
|
|
16386
|
+
}
|
|
16387
|
+
} catch (error) {
|
|
16388
|
+
logger2.warn(`Order ${order.id}: failed to check BTC liquidity, proceeding anyway: ${error.message}`);
|
|
16389
|
+
}
|
|
16390
|
+
try {
|
|
16391
|
+
const lockAcquired = await updateExchangeOrderWithExpectedStatus(
|
|
16392
|
+
order.id,
|
|
16393
|
+
order.status,
|
|
16394
|
+
{ status: EXCHANGE_ORDER_STATUS.BTC_SENDING }
|
|
16395
|
+
);
|
|
16396
|
+
if (!lockAcquired) {
|
|
16397
|
+
logger2.warn(`Order ${order.id}: optimistic lock failed on ${order.status} -> btc_sending, skipping`);
|
|
16398
|
+
return;
|
|
16399
|
+
}
|
|
16400
|
+
const result = await rgbClient.lightning.payInvoice({ invoice: order.btc_invoice });
|
|
16401
|
+
const resultError = result && (result.error || result.failure_reason);
|
|
16402
|
+
if (resultError) {
|
|
16403
|
+
const errMsg = typeof resultError === "string" ? resultError : JSON.stringify(resultError);
|
|
16404
|
+
const isPermanent = /route.*not.*found|no.?route|expired/i.test(errMsg);
|
|
16405
|
+
if (isPermanent) {
|
|
16406
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16407
|
+
order.id,
|
|
16408
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16409
|
+
{ status: EXCHANGE_ORDER_STATUS.FAILED, error_message: errMsg }
|
|
16410
|
+
);
|
|
16411
|
+
logger2.error(`Order ${order.id}: BTC payment permanently failed (from response): ${errMsg}`);
|
|
16412
|
+
} else {
|
|
16413
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16414
|
+
order.id,
|
|
16415
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16416
|
+
{
|
|
16417
|
+
status: EXCHANGE_ORDER_STATUS.RGB_PAID,
|
|
16418
|
+
btc_retry_count: retries + 1,
|
|
16419
|
+
error_message: errMsg
|
|
16420
|
+
}
|
|
16421
|
+
);
|
|
16422
|
+
logger2.warn(`Order ${order.id}: BTC payment failed (from response, retry ${retries + 1}/${MAX_BTC_RETRIES}): ${errMsg}`);
|
|
16423
|
+
}
|
|
16424
|
+
return;
|
|
16425
|
+
}
|
|
16426
|
+
const preimage = result && result.preimage ? result.preimage : null;
|
|
16427
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16428
|
+
order.id,
|
|
16429
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16430
|
+
{
|
|
16431
|
+
status: EXCHANGE_ORDER_STATUS.BTC_SENT,
|
|
16432
|
+
preimage,
|
|
16433
|
+
// Keep btc_retry_count — don't reset until completed.
|
|
16434
|
+
error_message: null
|
|
16435
|
+
}
|
|
16436
|
+
);
|
|
16437
|
+
if (!preimage) {
|
|
16438
|
+
logger2.warn(`Order ${order.id}: BTC payInvoice returned without preimage (retry ${retries}/${MAX_BTC_RETRIES}), payment may fail async`);
|
|
16439
|
+
} else {
|
|
16440
|
+
logger2.info(`Order ${order.id}: BTC payment sent, preimage=${preimage}`);
|
|
16441
|
+
}
|
|
16442
|
+
} catch (error) {
|
|
16443
|
+
const isTimeout = /timeout|ETIMEDOUT|ECONNRESET|socket hang up/i.test(error.message);
|
|
16444
|
+
if (isTimeout) {
|
|
16445
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16446
|
+
order.id,
|
|
16447
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16448
|
+
{ error_message: `Ambiguous: ${error.message} \u2014 will re-check next tick` }
|
|
16449
|
+
);
|
|
16450
|
+
logger2.warn(`Order ${order.id}: BTC sendpayment ambiguous timeout, keeping btc_sending for re-check`);
|
|
16451
|
+
return;
|
|
16452
|
+
}
|
|
16453
|
+
const isAlreadyPaid = /already paid/i.test(error.message);
|
|
16454
|
+
if (isAlreadyPaid) {
|
|
16455
|
+
const matchedPayment = payments.find(
|
|
16456
|
+
(p) => p.payment_hash === order.payment_hash && p.inbound === false && p.status === "Succeeded"
|
|
16457
|
+
);
|
|
16458
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16459
|
+
order.id,
|
|
16460
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16461
|
+
{
|
|
16462
|
+
status: EXCHANGE_ORDER_STATUS.BTC_SENT,
|
|
16463
|
+
preimage: matchedPayment?.preimage || null,
|
|
16464
|
+
btc_retry_count: 0,
|
|
16465
|
+
error_message: null
|
|
16466
|
+
}
|
|
16467
|
+
);
|
|
16468
|
+
logger2.warn(`Order ${order.id}: BTC "already paid" \u2014 treating as success, advanced to btc_sent`);
|
|
16469
|
+
return;
|
|
16470
|
+
}
|
|
16471
|
+
const isPermanent = /expired|no route/i.test(error.message);
|
|
16472
|
+
if (isPermanent) {
|
|
16473
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16474
|
+
order.id,
|
|
16475
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16476
|
+
{ status: EXCHANGE_ORDER_STATUS.FAILED, error_message: error.message }
|
|
16477
|
+
);
|
|
16478
|
+
logger2.error(`Order ${order.id}: BTC sendpayment permanently failed: ${error.message}`);
|
|
16479
|
+
} else {
|
|
16480
|
+
await updateExchangeOrderWithExpectedStatus(
|
|
16481
|
+
order.id,
|
|
16482
|
+
EXCHANGE_ORDER_STATUS.BTC_SENDING,
|
|
16483
|
+
{
|
|
16484
|
+
status: EXCHANGE_ORDER_STATUS.RGB_PAID,
|
|
16485
|
+
btc_retry_count: retries + 1,
|
|
16486
|
+
error_message: error.message
|
|
16487
|
+
}
|
|
16488
|
+
);
|
|
16489
|
+
logger2.warn(`Order ${order.id}: BTC sendpayment transient error (retry ${retries + 1}/${MAX_BTC_RETRIES}), will retry: ${error.message}`);
|
|
16490
|
+
}
|
|
16491
|
+
}
|
|
16492
|
+
}
|
|
16493
|
+
__name(sendBtcPayment, "sendBtcPayment");
|
|
16494
|
+
module2.exports = pollExchangeOrders;
|
|
16495
|
+
}
|
|
16496
|
+
});
|
|
16497
|
+
|
|
15743
16498
|
// business/job/rgb/pollLightningTransfers.js
|
|
15744
16499
|
var require_pollLightningTransfers = __commonJS({
|
|
15745
16500
|
"business/job/rgb/pollLightningTransfers.js"(exports2, module2) {
|
|
@@ -16634,6 +17389,7 @@ var require_tasks = __commonJS({
|
|
|
16634
17389
|
var pollInvoiceTransfers = require_pollInvoiceTransfers();
|
|
16635
17390
|
var rgbConnectPeer = require_connectPeer2();
|
|
16636
17391
|
var pollBtcTransfers = require_pollBtcTransfers2();
|
|
17392
|
+
var pollExchangeOrders = require_pollExchangeOrders();
|
|
16637
17393
|
var pollLightningTransfers = require_pollLightningTransfers();
|
|
16638
17394
|
var pollRgbTransfers = require_pollRgbTransfers();
|
|
16639
17395
|
var refreshTransfers = require_refreshTransfers();
|
|
@@ -16762,6 +17518,17 @@ var require_tasks = __commonJS({
|
|
|
16762
17518
|
timeout: 3e4,
|
|
16763
17519
|
description: "Poll RGB Lightning transfers"
|
|
16764
17520
|
},
|
|
17521
|
+
rgb_poll_exchange_orders: {
|
|
17522
|
+
type: "cron",
|
|
17523
|
+
schedule: "*/5 * * * * *",
|
|
17524
|
+
implementation: pollExchangeOrders,
|
|
17525
|
+
gate: "rgbActive",
|
|
17526
|
+
priority: 1,
|
|
17527
|
+
enabled: true,
|
|
17528
|
+
maxRetries: 3,
|
|
17529
|
+
timeout: 3e4,
|
|
17530
|
+
description: "Poll RGB-BTC exchange orders and trigger BTC sendpayment on RGB receipt"
|
|
17531
|
+
},
|
|
16765
17532
|
// Event-driven tasks
|
|
16766
17533
|
bake_tapd_macaroon: {
|
|
16767
17534
|
type: "event",
|
|
@@ -19238,7 +20005,8 @@ var require_setting_mainnet = __commonJS({
|
|
|
19238
20005
|
officialRgbPeerHost: "CHANGE_ME_MAINNET_RGB_HOST:9736",
|
|
19239
20006
|
officialUniverseServer: "CHANGE_ME_MAINNET_UNIVERSE_HOST:10009",
|
|
19240
20007
|
priceOracle: "grpc-oracle.lnfi.network",
|
|
19241
|
-
rgbProxy: "rpc://CHANGE_ME_MAINNET_RGB_PROXY_HOST:5000/json-rpc"
|
|
20008
|
+
rgbProxy: "rpc://CHANGE_ME_MAINNET_RGB_PROXY_HOST:5000/json-rpc",
|
|
20009
|
+
rgbPriceServer: "https://api-oracle.lnfi.network"
|
|
19242
20010
|
};
|
|
19243
20011
|
}
|
|
19244
20012
|
});
|
|
@@ -19256,17 +20024,18 @@ var require_setting_regtest = __commonJS({
|
|
|
19256
20024
|
bitcoindZmqRawTx: "tcp://regtest.lnfi.network:28335",
|
|
19257
20025
|
network: "regtest",
|
|
19258
20026
|
nostrRelays: [
|
|
19259
|
-
"wss://
|
|
19260
|
-
"wss://
|
|
20027
|
+
"wss://relay01.lnfi.network",
|
|
20028
|
+
"wss://vault.iris.to"
|
|
19261
20029
|
],
|
|
19262
20030
|
officialLndPeer: "03b24a4bf911ffd26ac1d5e5f2440a3c2f6974e4cc85d2ef54e17ee6d3717433d3",
|
|
19263
|
-
officialLndPeerHost: "34.84.
|
|
20031
|
+
officialLndPeerHost: "34.84.69.164:7739",
|
|
19264
20032
|
officialNostrPubKey: "npub1me48869w43j30cfry9ayz9dsdl4gj54xppgk9krrv7g6hsq7psuqp3yusn",
|
|
19265
20033
|
officialRgbPeer: "03b7153e278882e48e690acd0743305cbada86b131ab3388ccd782b45b02f064ef",
|
|
19266
20034
|
officialRgbPeerHost: "regtest.lnfi.network:9736",
|
|
19267
20035
|
officialUniverseServer: "regtest.lnfi.network:10009",
|
|
19268
20036
|
priceOracle: "grpc-oracle.lnfi.network",
|
|
19269
|
-
rgbProxy: "rpc://regtest.lnfi.network:5000/json-rpc"
|
|
20037
|
+
rgbProxy: "rpc://regtest.lnfi.network:5000/json-rpc",
|
|
20038
|
+
rgbPriceServer: "https://api-oracle.lnfi.network"
|
|
19270
20039
|
};
|
|
19271
20040
|
}
|
|
19272
20041
|
});
|
|
@@ -19294,7 +20063,8 @@ var require_setting_testnet = __commonJS({
|
|
|
19294
20063
|
officialRgbPeerHost: "CHANGE_ME_TESTNET_RGB_HOST:9736",
|
|
19295
20064
|
officialUniverseServer: "CHANGE_ME_TESTNET_UNIVERSE_HOST:10009",
|
|
19296
20065
|
priceOracle: "grpc-oracle.lnfi.network",
|
|
19297
|
-
rgbProxy: "rpc://CHANGE_ME_TESTNET_RGB_PROXY_HOST:5000/json-rpc"
|
|
20066
|
+
rgbProxy: "rpc://CHANGE_ME_TESTNET_RGB_PROXY_HOST:5000/json-rpc",
|
|
20067
|
+
rgbPriceServer: "https://api-oracle.lnfi.network"
|
|
19298
20068
|
};
|
|
19299
20069
|
}
|
|
19300
20070
|
});
|
|
@@ -19328,6 +20098,16 @@ var require_initLinkConfig = __commonJS({
|
|
|
19328
20098
|
await updateMainLnlinkConfig({ node_name: LINK_NAME });
|
|
19329
20099
|
await reloadConfig();
|
|
19330
20100
|
}
|
|
20101
|
+
const networkTemplate = LINK_NETWORK === "testnet" ? testnetSettings : LINK_NETWORK === "mainnet" ? mainnetSettings : regtestSettings;
|
|
20102
|
+
const missingKeys = Object.keys(networkTemplate).filter(
|
|
20103
|
+
(k) => !(k in lndConfig.settings)
|
|
20104
|
+
);
|
|
20105
|
+
if (missingKeys.length > 0) {
|
|
20106
|
+
const patch = Object.fromEntries(missingKeys.map((k) => [k, networkTemplate[k]]));
|
|
20107
|
+
await updateMainLnlinkConfig({ settings: { ...lndConfig.settings, ...patch } });
|
|
20108
|
+
await reloadConfig();
|
|
20109
|
+
logger2.info(`Settings patched with new keys: ${missingKeys.join(", ")}`);
|
|
20110
|
+
}
|
|
19331
20111
|
return;
|
|
19332
20112
|
}
|
|
19333
20113
|
let settings;
|