This project is an SDK library developed based on the Nostr Asset Protocol, designed to facilitate interactions with Lightning Network Daemon (LND) and RGB nodes, enabling Nostr-based functionalities.
npm install lnlink-serverThis project is an SDK library developed based on the Nostr Asset Protocol, designed to facilitate interactions with Lightning Network Daemon (LND) and RGB nodes, enabling Nostr-based functionalities.
- Node.js >= 19
- Yarn >= 1.22
Install project dependencies once at the repository root:
``bash`
yarn install
Notes:
- Native deps such as @prisma/client are required at runtime and are not bundled by esbuild.litd
- Binaries (, rgb-lightning-node, tor) are prepared by scripts/binSetup.js on demand.
There are three ways to start the project. Choose the one that fits your scenario.
This mode runs everything on your host using local binaries. It is the fastest way to try the project.
- Prerequisites
- Node.js >= 19
- The project will download platform-specific binaries automatically on first run.
- Prepare env file at project root: .env.binLINK_BINARY_PATH=/
- Common variables:
- or an absolute path, e.g. /root/data/binLINK_NAME=...
- LINK_DATA_PATH=/root/data/
- or an absolute pathLINK_HTTP_PORT=8099
- LINK_ENABLE_TOR=false
- (optional)LINK_OWNER
- : Nostr npub of the owner/operatorLINK_NETWORK
- : Bitcoin network (regtest, testnet, mainnet)
- Install deps (first time only)
`bash`
yarn install
- Start
`bash`
yarn start:bin
scripts/binSetup.js
What happens:
- runs first to ensure required binaries exist (downloads using binaries.json)..env.bin
- The app then starts with variables loaded from .
Use this for local development and debugging with Docker.
- Prepare env file at project root: .env.dev.env.dev
- Environment variables overview ():LINK_NAME
- : Logical name of this node instance. Used to name Docker volumes and service identifiers.LINK_DATA_PATH
- : Absolute path to persist data (wallet, db, macaroons, etc.). Prefer an absolute path to avoid ambiguity.LINK_OWNER
- : Nostr npub of the owner/operator.LINK_NETWORK
- : Bitcoin network. Typical values: regtest, testnet, mainnet.LINK_ENABLE_TOR
- : Whether to enable Tor support (true/false).LINK_HTTP_PORT
- : API HTTP port exposed by this wrapper inside Docker to your host.LINK_LND_RPC_PORT
- : LND gRPC port exposed to the host.LINK_RGB_LISTENING_PORT
- : RGB service port exposed to the host.LINK_NODE_ENV
- : Node.js runtime environment, typically development for this mode.LINK_NOSTR_NODE_NPUBKEY
- : The npub (hex-encoded pubkey) of the Nostr relay/node this instance peers with.LINK_NOSTR_NODE_HOST
- : The Nostr Lightning node host (pubkey@host:port or host:port) used for peering.LINK_ORACLE_SERVER_HOST
- : Oracle/bridge service host for price or external queries if applicable.LINK_BITCOIND_RPCHOST
- : Bitcoind RPC host (host:port) that LND connects to (for regtest/testnet/mainnet as configured).LINK_BITCOIND_RPCUSER
- : Bitcoind RPC username.LINK_BITCOIND_RPCPASS
- : Bitcoind RPC password.LINK_BITCOIND_ZMQBLOCK
- : Bitcoind ZMQ block notifications endpoint.LINK_BITCOIND_ZMQRAWTX
- : Bitcoind ZMQ raw transaction notifications endpoint.
- Example .env.dev (regtest):`
env
LINK_NAME=
LINK_DATA_PATH='/
LINK_DATABASE_URL=file:/
LINK_OWNER=npub1q7amuklx0fjw76dtulzzhhjmff8du5lyngw377d89hhrmj49w48ssltn7y
LINK_NETWORK=regtest
LINK_ENABLE_TOR=false
LINK_HTTP_PORT=8090
LINK_LND_RPC_PORT=30009
LINK_RGB_LISTENING_PORT=5002
LINK_NODE_ENV=development
LINK_NOSTR_NODE_NPUBKEY=027d2f1be71dc24c60b15070489d4ef274dd6aac236d02c67c76d6935defba56a6
LINK_NOSTR_NODE_HOST=regtest.lnfi.network:9735
LINK_ORACLE_SERVER_HOST=grpc-oracle.lnfi.network:443
LINK_BITCOIND_RPCHOST=regtest.lnfi.network:18443
LINK_BITCOIND_RPCUSER=lnfi_user
LINK_BITCOIND_RPCPASS=lnfi_pass12GA
LINK_BITCOIND_ZMQBLOCK=tcp://regtest.lnfi.network:28334
LINK_BITCOIND_ZMQRAWTX=tcp://regtest.lnfi.network:28335
`
- Start
`bash`
yarn start:docker:dev
.env.dev
This will:
- Use for environment variables.docker-compose.dev.yml
- Launch services defined in .
Run steps (recommended workflow):
1) Start dependencies (Docker services) in Terminal A:
`bash`
yarn start:docker:dev
.env.dev
2) Start the application in Terminal B (local Node process using ):`
bash`
yarn start:dev
Stop / cleanup:
- Stop the application: Ctrl+C in the Terminal B running yarn start:dev.`
- Stop Docker services:
bash`
docker compose --env-file ./.env.dev -f ./docker-compose.dev.yml down
Network prerequisite:
- The compose file uses an external Docker network named lnfi_network. Create it once if it doesn't exist:`
bash`
docker network create lnfi_network
Tips:
- Ensure LINK_DATA_PATH exists and is writable by Docker; it will persist LND/RGB data and macaroons.LINK_HTTP_PORT
- Make sure the specified ports (, LINK_LND_RPC_PORT, LINK_RGB_LISTENING_PORT) are free on your host.regtest
- For , confirm your BITCOIND_* endpoints are reachable from the Docker network.
Use this when you want to run LN-Link fully inside Docker with a clear separation between
environment settings (.env.*) and network profiles (DB settings).
There are three environment files for different networks:
- .env.regtest.env.testnet
- .env.mainnet
- (optional, usually only contains non-sensitive runtime values)
Each file typically contains:
- LINK_NAME: Logical name of this node instance (used for container/alias/naming).LINK_NETWORK
- : Bitcoin network (regtest, testnet, mainnet).LINK_DATA_PATH
- : Data persistence path (relative path supported, e.g. ./docker/volumes/linkdev).LINK_OWNER
- : Nostr npub of the owner/operator.LINK_ENABLE_TOR
- : Enable Tor support (true/false).LINK_RGB_LDK_PEER_LISTENING_PORT
- : RGB LDK peer listening port (e.g. 9750).LINK_RGB_HOST
- : Host advertised for RGB peers (e.g. host LAN IP in regtest).LINK_REPORT_BASE_URL
- , LINK_REPORT_ADDRESS: Optional reporting/telemetry endpoints.
Example .env.regtest:
`env
LINK_NAME=linkdev
LINK_NETWORK=regtest
LINK_NODE_ENV=production
LINK_DATA_PATH=./docker/volumes/linkdev
LINK_ENABLE_TOR=false
LINK_OWNER=npub1...
LINK_REPORT_BASE_URL=https://devoffaucet.unift.xyz
LINK_REPORT_ADDRESS=npub1...
LINK_RGB_LDK_PEER_LISTENING_PORT=9750
LINK_RGB_HOST=192.168.0.117
`
Example .env.testnet is similar but typically uses a different LINK_DATA_PATH and
possibly different ports/host IP.
- Start (regtest)
`bash`
yarn start:regtest
- Start (testnet)
`bash`
yarn start:testnet
- Start (mainnet)
`bash`
# Requires a proper .env.mainnet and network settings (see LINK_SETTINGS_PATH below)
yarn start:mainnet
Each command will:
- Use the corresponding .env. file via docker-compose-lnlink.yml.lit
- Launch the service (LN-Link + litd + RGB) inside Docker on thelnfi_network
external network .
Build first:
`bash`
yarn build
Run using local binaries and env .env.bin (requires bin/ and root node_modules/):
`bash`
yarn start:bin:dist
Notes about dist/ runtime:dist/index.js
- still requires runtime dependencies from the repository root node_modules/ (e.g., @grpc/grpc-js, @prisma/client).proto/
- The folder is copied to dist/proto/ during build; code resolves proto paths via process.cwd().bin/
- The folder (with litd, rgb-lightning-node, tor) is required when running with local binaries; prepare it using yarn start:bin once, or run node ./scripts/binSetup.js.
After building with yarn build, the dist/ directory contains a complete NPM package that can be published and used in other projects.
`bash`
npm install @lnfi-network/ln-link
Note: Database initialization (Prisma client generation and migrations) is handled at runtime to avoid requiring environment variables during package installation.
`javascript
// Import the main application entry point
require('@lnfi-network/ln-link');
// The application will start automatically when imported
// Configuration is handled via environment variables or config files
`
For programmatic control in Node.js:
`javascript
const path = require('path');
// Set environment variables before importing
process.env.LINK_DATA_PATH = path.join(__dirname, 'ln-link-data');
process.env.LINK_NETWORK = 'testnet';
process.env.LINK_HTTP_PORT = '8099';
process.env.LINK_OWNER = 'npub1...'; // Your Nostr public key
process.env.LINK_DATABASE_URL = 'file:' + path.join(__dirname, 'ln-link-data', 'lnlink.db');
// You may need to run Prisma setup manually for Node.js applications:
// npx prisma generate
// npx prisma migrate deploy
// Import and start the application
require('@lnfi-network/ln-link');
`
The package provides a dedicated Electron entry point for desktop applications:
`javascript
// In your Electron main process
const { app, BrowserWindow } = require('electron');
const path = require('path');
// Import the Electron-specific entry point
const LnLinkElectron = require('@lnfi-network/ln-link/electron');
// Global LN-Link instance
let lnLink = null;
app.whenReady().then(async () => {
// Create your Electron window
const mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
// Create LN-Link instance
lnLink = new LnLinkElectron({
dataPath: path.join(app.getPath('userData'), 'ln-link'),
network: 'testnet', // or 'mainnet', 'regtest'
httpPort: 8099,
name: 'my-electron-app',
enableTor: false,
owner: 'npub1...', // Your Nostr public key
debug: true,
// binaryPath: '/path/to/binaries', // Optional: for local binary mode
// Database setup is handled automatically in Electron applications
});
await lnLink.start();
// Load your application UI
mainWindow.loadFile('index.html');
});
app.on('window-all-closed', async () => {
// Gracefully shutdown LN-Link
if (lnLink) {
await lnLink.stop();
}
if (process.platform !== 'darwin') {
app.quit();
}
});
`
When using the package in other applications, you can configure it programmatically:
`javascript
const config = {
// Data storage path
dataPath: '/path/to/data',
// Network configuration
network: 'testnet', // 'mainnet', 'testnet', 'regtest'
// Application name
name: 'my-app',
// Service ports
httpPort: 8099,
lndRpcPort: 10009,
rgbPort: 5002,
// Nostr configuration
owner: 'npub1...', // Your Nostr public key
// Optional features
enableTor: false,
debug: false,
// Binary paths (for local binary mode)
binaryPath: '/path/to/binaries',
// Database configuration (optional - defaults to dataPath/lnlink.db)
databaseUrl: 'file:/path/to/custom/database.db',
};
LN-Link stores the network profile (bitcoind, RGB, Nostr, oracle, etc.) in the
LnlinkConfig.settings field in the database. At runtime, getConfig() merges:
- config.default.js (built-in defaults).env.*
- Process env ( / programmatic options)LnlinkConfig.settings
- (network profile)
For Docker/standalone modes (LINK_NODE_ENV !== "app"):
- On first start, if the DB has no settings, LN-Link will initialize them by:LINK_SETTINGS_PATH
1. If is set and points to a valid JSON file, load that JSONLnlinkConfig.settings
and write it to .setting.regtest.json
2. Otherwise, fall back to network templates:
- for LINK_NETWORK=regtestsetting.testnet.json
- for LINK_NETWORK=testnetsetting.mainnet.json
- for LINK_NETWORK=mainnet (template only, no secrets).
For security-sensitive environments (especially mainnet):
- Keep setting.mainnet.json as a template only (with placeholder values)./data/config/lnlink-mainnet-settings.json
- Put the real mainnet JSON under a secure path on the server, e.g.:
- `
- Set:
env`
LINK_NETWORK=mainnet
LINK_SETTINGS_PATH=/data/config/lnlink-mainnet-settings.json
LnlinkConfig.settings
so that first start reads this file and writes it into .
The human-readable node name comes from LnlinkConfig.node_name and is exposed asLINK_NAME by getConfig() with the following precedence:
- DB node_name > env LINK_NAME > config.default.js.
On first initialization in Docker/standalone mode:
- LN-Link uses the current LINK_NAME to populate LnlinkConfig.node_name.settings
- If already exist but node_name is empty, it will backfillnode_name
once from the current LINK_NAME.
To change the node name later without touching env:
- Use the HTTP API:
`http`
POST /api/lnd/update-name
{ "nodeName": "my-new-node-name" }
LnlinkConfig.node_name
This updates and triggers reloadConfig(), sogetConfig()
subsequent calls see the new LINK_NAME immediately.
Notes:
- LND (litd) reads the alias/TLS extra domains only at process start
(via buildLitdArgs). Changing the name via API does not automaticallyLINK_NAME
restart litd; restart is only needed if you want the alias/TLS SANs to match
the new name.
- RGB uses as announce_alias during unlockNode. After changing
the name, the next unlock call will use the new alias; no process restart
is required for RGB.
When running via the Electron entry point (lnlink.js / LnLinkElectron):
- LINK_NODE_ENV is effectively "app".initLinkConfig()
- does not auto-initialize DB from setting.*.json orLINK_SETTINGS_PATH
.LnlinkConfig.settings
- You are expected to initialize and update andnode_name
via the HTTP APIs:POST /api/lnd/init
- with { owner, settings, nodeName }.POST /api/lnd/update-name
- with { nodeName }.`
- Prisma: Database client generation and migrations are handled at runtime. For Node.js applications, you may need to run manually:
`bash`
npx prisma generate # Generate client code
npx prisma migrate deploy # Apply database migrations
For Electron applications, database setup is handled automatically.
- Binary Dependencies: When using local binaries (LND, RGB node, Tor), ensure they are available for your target platform. The package includes platform detection and automatic binary management.
- Local binary workflow
- The binary download/prepare workflow is implemented in scripts/binSetup.js (calls scripts/binManage.js).binaries.json
- Download sources are configured in per-platform (darwin-arm64, darwin-x64, linux-x64)../bin
- Binaries are stored under by default; you can override via LINK_BINARY_PATH.startJobs
- Job system
- The system initializes with state-driven tasks; no manual events are needed.business/job/core/StateManager.js` for better diagnostics.
- Error handling
- Improved error typing in