Progress pill
Building on RGB

RLN - RGB Lightning Node

RGB programming

RLN - RGB Lightning Node

  • Deploying an RGB-compatible Lightning node
  • Introducing rgb-lightning-node
  • Node installation
  • Performance requirements
  • Regtest launch
  • Testnet launch (without Docker)
  • Issuing an RGB token
  • Opening a channel and transferring an RGB asset
In this final chapter, Frederico Tenga takes you step-by-step through setting up a Lightning RGB node on a Regtest environment, and shows you how to create RGB tokens on it. By launching two separate nodes, you'll also discover how to open a Lightning channel between them and exchange RGB assets.
This video serves as a tutorial, similar to what we covered in a previous chapter, but specifically focused on Lightning this time!
The main resource for this video is the Github repository RGB Lightning Node, which makes it easy for you to launch this configuration in Regtest.

Deploying an RGB-compatible Lightning node

The process takes up and puts into practice all the concepts covered in the previous chapters:
  • The idea that UTXO blocked on a 2/2 multisig of a Lightning channel can receive not only bitcoins, but also be a Single-use Seal of RGB assets (fungible or not);
  • The addition, in each Lightning engagement transaction, of an output (Tapret or Opret) dedicated to anchoring the RGB state transition;
  • The associated infrastructure (bitcoind/indexer/proxy) to validate Bitcoin transactions and exchange client-side data.

Introducing rgb-lightning-node

The rgb-lightning-node project is a Rust daemon based on an rust-lightning (LDK) fork modified to take into account the existence of RGB assets in a channel. When a channel is opened, the presence of assets can be specified, and each time the channel state is updated, an RGB transition is created, reflecting the distribution of the asset in the Lightning outputs. This enables:
  • Open Lightning channels in USDT, for example;
  • Route these tokens through the network, provided the routing paths have sufficient liquidity;
  • Exploit Lightning's punishment and timelock logic without modification: simply anchor the RGB transition in an additional output of the commitment transaction.
The code is still at the alpha stage: we recommend using it in regtest or on the testnet only.

Node installation

To compile and install the rgb-lightning-node binary, we start by cloning the repository and its sub-modules, then we run the command:
git clone https://github.com/RGB-Tools/rgb-lightning-node --recurse-submodules --shallow-submodules
  • The --recurse-submodules option also clones the necessary sub-devices (including the modified version of rust-lightning);
  • The --shallow-submodules option restricts the depth of the clone to speed up downloading, while still providing access to essential commits.
From the project root, run the following command to compile and install the binary:
cargo install --locked --debug --path .
  • --locked ensures that the version of dependencies is strictly respected;
  • --debug is not compulsory, but can help you focus (you can use --release if you prefer);
  • --path . tells cargo install to install from the current directory.
At the end of this command, an rgb-lightning-node executable will be available in your $CARGO_HOME/bin/. Make sure this path is in your $PATH so you can invoke the command from any directory.

Performance requirements

To function, the rgb-lightning-node daemon requires the presence and configuration of:
  • A bitcoind node
Each RLN instance will need to communicate with bitcoind to broadcast and monitor its on-chain transactions. Authentication (login/password) and URL (host/port) will need to be provided to the daemon.
  • An indexer (Electrum or Esplora)
The daemon must be able to list and explore on-chain transactions, in particular to find the UTXO on which an asset has been anchored. You'll need to specify the URL of your Electrum server or Esplora.
  • An RGB proxy
As seen in previous chapters, the proxy server is a component (optional, but highly recommended) to simplify the exchange of consignments between Lightning peers. Once again, a URL must be specified.
IDs and URLs are entered when the daemon is unlocked via the API. More on this later.

Regtest launch

For simple use, there's a regtest.sh script that automatically starts, via Docker, a set of services: bitcoind, electrs (indexer), rgb-proxy-server.
This allows you to launch a local, isolated, pre-configured environment. It creates and destroys containers and data directories on each reboot. We'll begin by starting the:
./regtest.sh start
This script will:
  • Create a docker/ directory to store;
  • Run bitcoind in regtest, as well as the indexer electrs and the rgb-proxy-server;
  • Wait until everything is ready to use.
Next, we'll launch several RLN nodes. In separate shells, run, for example (to launch 3 RLN nodes):
# 1st shell rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \ --ldk-peer-listening-port 9735 --network regtest # 2nd shell rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \ --ldk-peer-listening-port 9736 --network regtest # 3rd shell rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \ --ldk-peer-listening-port 9737 --network regtest
  • The --network regtest parameter indicates the use of the regtest configuration;
  • --daemon-listening-port indicates on which REST port the Lightning node will listen for API calls (JSON);
  • --ldk-peer-listening-port specifies which Lightning p2p port to listen on;
  • dataldk0/, dataldk1/ are the paths to the storage directories (each node stores its info separately).
You can also run commands on your RLN nodes from your browser:
https://rgb-tools.github.io/rgb-lightning-node/
For a node to open a channel, it must first have bitcoins on an address generated with the following command (for node n°1, for example):
curl -X POST http://localhost:3001/address
The answer will provide you with an address.
On the bitcoind Regtest, we're going to mine a few bitcoins. Run:
./regtest.sh mine 101
Send funds to the node address generated above:
./regtest.sh sendtoaddress <address> <amount>
Then mine a block to confirm the transaction:
./regtest.sh mine 1

Testnet launch (without Docker)

If you want to test a more realistic scenario, you can launch 3 RLN nodes on the Testnet rather than in Regtest, pointing to public services:
rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \ --ldk-peer-listening-port 9735 --network testnet rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \ --ldk-peer-listening-port 9736 --network testnet rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \ --ldk-peer-listening-port 9737 --network testnet
By default, if no configuration is found, the daemon will try to use the following:
  • bitcoind_rpc_host: electrum.iriswallet.com
  • bitcoind_rpc_port: 18332
  • indexer_url: ssl://electrum.iriswallet.com:50013
  • proxy_endpoint: rpcs://proxy.iriswallet.com/0.2/json-rpc
With login:
  • bitcoind_rpc_username: user
  • bitcoind_rpc_username: password
You can also customize these elements via the init/unlock API.

Issuing an RGB token

To issue a token, we'll start by creating "colorable" UTXOs:
curl -X POST -H "Content-Type: application/json" \ -d '{ "up_to": false, "num": 4, "size": 2000000, "fee_rate": 4.2, "skip_sync": false }' \ http://localhost:3001/createutxos
You can, of course, adapt the order. To confirm the transaction, we will mine a block:
./regtest.sh mine 1
We can now create an RGB asset. The command will depend on the type of asset you wish to create and its parameters. Here I'm creating a NIA (Non Inflatable Asset) token named "Plan ₿ Academy" with a supply of 1000 units. The precision allows you to define the divisibility of the units.
curl -X POST -H "Content-Type: application/json" \ -d '{ "amounts": [ 1000 ], "ticker": "Plan ₿ Academy", "name": "Plan ₿ Academy", "precision": 0 }' \ http://localhost:3001/issueassetnia
The response includes the ID of the newly created asset. Remember to note this identifier. In my case, it's:
rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10
You can then transfer it on-chain, or allocate it in a Lightning channel. That's exactly what we're going to do in the next section.

Opening a channel and transferring an RGB asset

You must first connect your node to a peer on the Lightning network using the /connectpeer command. In my example, I control both nodes. So I'll retrieve the public key of my second Lightning node with this command:
curl -X 'GET' \ 'http://localhost:3002/nodeinfo' \ -H 'accept: application/json'
The command returns the public key of my node n°2:
031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94
Next, we'll open the channel by specifying the relevant asset (Plan ₿ Academy). The /openchannel command lets you define the size of the channel in satoshis and opt to include the RGB asset. It depends on what you want to create, but in my case, the command is:
curl -X POST -H "Content-Type: application/json" \ -d '{ "peer_pubkey_and_opt_addr": "031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94@localhost:9736", "capacity_sat": 1000000, "push_msat": 10000000, "asset_amount": 500, "asset_id": "rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10", "public": true, "with_anchors": true, "fee_base_msat": 1000, "fee_proportional_millionths": 0, "temporary_channel_id": "a8b60c8ce3067b5fc881d4831323e24751daec3b64353c8df3205ec5d838f1c5" }' \ http://localhost:3001/openchannel
Find out more here:
  • peer_pubkey_and_opt_addr: Identifier of the peer we wish to connect to (the public key we found earlier);
  • capacity_sat: Total channel capacity in satoshis;
  • push_msat: Amount in millisatoshis initially transferred to the peer when the channel is opened (here I immediately transfer 10,000 sats so that he can make an RGB transfer later);
  • asset_amount: Amount of RGB assets to be committed to the channel;
  • asset_id: Unique identifier of the RGB asset engaged in the channel;
  • public: Indicates whether the channel should be made public for routing on the network.
To confirm the transaction, 6 blocks are mined:
./regtest.sh mine 6
The Lightning channel is now open and also contains 500 Plan ₿ Academy tokens on node n°1's side. If node n°2 wishes to receive Plan ₿ Academy tokens, it must generate an invoice. Here's how to do it:
curl -X POST -H "Content-Type: application/json" \ -d '{ "amt_msat": 3000000, "expiry_sec": 420, "asset_id": "rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10", "asset_amount": 100 }' \ http://localhost:3002/lninvoice
With:
  • amt_msat: Invoice amount in millisatoshis (minimum 3000 sats);
  • expiry_sec: Invoice expiry time in seconds;
  • asset_id: Identifier of the RGB asset associated with the invoice;
  • asset_amount: Amount of RGB asset to be transferred with this invoice.
In response, you will get an RGB invoice (as described in previous chapters):
lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj
We will now pay this invoice from the first node, which holds the necessary cash with the Plan ₿ Academy token:
curl -X POST -H "Content-Type: application/json" \ -d '{ "invoice": "lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj" }' \ http://localhost:3001/sendpayment
Payment has been made. This can be verified by executing the command:
curl -X 'GET' \ 'http://localhost:3001/listpayments' \ -H 'accept: application/json'
Here's how to deploy a Lightning node modified to carry RGB assets. This demonstration is based on:
  • A regtest environment (via ./regtest.sh) or testnet;
  • A Lightning node (rgb-lightning-node) based on a bitcoind, an indexer and an rgb-proxy-server;
  • A series of JSON REST APIs for opening/closing channels, issuing tokens, transferring assets via Lightning, etc.
Thanks to this process:
  • Lightning engagement transactions include an additional output (OP_RETURN or Taproot) with the anchoring of an RGB transition;
  • Transfers are made in exactly the same way as traditional Lightning payments, but with the addition of an RGB token;
  • Multiple RLN nodes can be linked to route and experiment with payments across multiple nodes, provided there is sufficient liquidity in both bitcoins and asset RGB on the path.
The project remains in the alpha stage. It is therefore strongly recommended that you limit yourself to test environments (regtest, testnet).
The opportunities opened up by this LN-RGB compatibility are considerable: stablecoins on Lightning, DEX layer-2, transfer of fungible tokens or NFTs at very low cost... The previous chapters have outlined the conceptual architecture and validation logic. Now you have a practical view of how to get such a node up and running, for your future developments or tests.
Quiz
Quiz1/5
On RLN, which command installs the "rgb-lightning-node" binary after cloning the repository?