Ring of Fire
A ring of fire is a circle of equal balanced channels. By forming a circle, your node gets better connected within the network and make a profit by routing transactions.
Ring of fire theory
To route transactions, you'll need both incoming and outgoing liquidity. Always try to open channels with nodes that carry a proper reputation. The BOS score on indexes such as 1ML gives you an idea of reputation but it is still difficult to check at this stage.
Best practices
It is important to realise that a ring of fire only works when all nodes remain connected to the network. If a node goes offline or a participant closes a channel, the route will be interrupted. With Satoshi Radio, the largest bitcoin community in the Netherlands, we came to a sweet spot of around 8-10 people.
Roles
Each ring of fire has its own ringleader. A ringleader guides the process and carries out the steps which need to be done using terminal. All participants ensure they pass on the information requested by our ringleader and make sure they are available during the proces in case any actions need to be performed.
Before we start
The ringleader will determine who will connect with whom and makes up the channel direction. A diagram like the one below will really help your group to understand their position within the ring.

Step 1: collect information
The ringleader is responsible to collect all node information from each ring member and place them in the pinned overview group message.
@ringleader: Make sure all participants have 500000 sats + network fee ready (on-chain).
All members claim their node with @cheeserobot in a Telegram DM using the following steps:
1. Send a DM with the text /claim
space your node ID
to @cheeserobot

2. @cheeserobot will ask to sign a message. Open the Ride the Lightning app with Umbrel and sign the message.

3. Copy your signature in RTL and send @cheeserobot the following command /claim
space your node ID
space signature

4. Your node is now claimed!

5. Open your ring of fire telegram group and share your node details by entering the following command: /node
your ringleader needs this information to get started.
6. The ringleader pins a message with all node information using the same order we made in our diagram and monitors if all nodes are tor enabled + funded before we go to step 2.
@ringleader: Make sure nobody opens a channel yet!
🧅🙌🏻@I2Sappig 02b6b8e6b683811f358e9602f8271694951b92dd66ff0841501f2ce9ddcf7bc2fc Alias: 2Sappig
🧅🙌🏻@stocktoflow 02e425b0102cwef0b8c1bce9d42001a41f615ad5we17247d57d1949bwefff3a4 Alias: BuidlBuidl
🧅🙌🏻@rebtorr 03bd5aef25b963cc256bdd009bc8084891e53cd067b781c68786f333e63a186e0f Alias: RebtoriaNode
🧅🙌🏻@udo327 03a97a8f6f2bd2293285474a4be48e8d971f333aa3183c95e51d0f704fd42fd92e Alias: udo327
🧅🙌🏻@PeteDoo 02258a9aa9463749bf729511af78b1ea339ecdb36b37a6e18a8c8caa895228bfcb Alias: on_fire
🧅🙌🏻Jupil 026b6cc74185ddc03cf5c57641b1c853dbab5fb2b738883c3891c5b4858f4e68b9 Alias: Jupil
🧅🙌🏻@stacktracey 025df45996b60d6f5a834f0963d2c3da6a0f187b7b434dc0cc3af46cf7956c3603 Alias: none
🧅🙌🏻@JJ 03581cae4671ebfc1d23fe971411216ee004102ab440069409c4748167ba96118e Alias: none
🧅🙌🏻@maartemmobiel 0334c4b3e5bc2c4677974561cc484f50181a5983cc956ceac473fb3f86c11f6299 Alias: none
🧅 Tor enabled 🙌🏻 Node topped up and ready to open a channel ⏳ Channel opening pending ✅ Channel established
Step 2: open channels
Look at our diagram to who you are going to open a channel. We go clockwise so in this case @l2sappig opens a channel of 50000 sats to @stocktoflow, @stocktoflow to @rebtorr and so on.

2. After establishing all channels, every ring member will open RTL and go to:
Lightning -> Peers/Channels -> Your channel -> Actions -> Update fee policy
Set base
and fee
to 0 and hit save.
3. Notify your ringleader in Telegram when your fee policy is changed.
Step 3: monitor node connections
Installing Ringtools
The following steps are only executed by our ringleader
Login using SSH
2. Upgrade pip
pip3 install --upgrade pip
3. Run command:
git clone https://github.com/StijnBTC/Ringtools
4. After downloading go to the Ringtools directory
cd Ringtools
5. Run command:
pip3 install -r requirements.txt
6. Run command:
sudo nano channels.txt
7. Replace everything in the file for the channel IDs you want to check. Look up the channel IDs of all channels, for example on 1ml.com.
In our case:
766994022803570689
766999520399654913
766992923372093441
767133660771254273
766994022803505153
767068789744009217
767000619939528705
766994022802128897
766995122387681281
8. Save this file by closing it with Ctrl
+X
and then Enter
and Y
to confirm.
9. Finally, run Ringtools with the following command:
python3 ringtools.py -f -l status
10. You will now see the overview of all nodes + their status. Make sure no nodes are red before continuing to step 4.


Make sure all (base) fees are set to 0 or 1 to avoid paying high fees when rebalancing in step 4.
To close Ringtools, hit Ctrl
+C
Resources
Step 4: rebalance
Now all nodes are connected we can start rebalancing our channels to make sure we have liquidity in both directions.
The following steps are only executed by our ringleader
Login using ssh
Download igniter
sudo wget https://raw.githubusercontent.com/RooSoft/igniter/main/igniter.sh
3. Enter the following command:
sudo chmod u+x igniter.sh
4. Enter the following command:
sudo nano igniter.sh
5. Edit line 7-15 of the script using the node ID's in order of our diagram. Change AMOUNT
(line 18) to half the channel size (500000 sats in our case) and change OUTGOING CHAIN ID
to your own (ringleader) outgoing channel ID.
#!/bin/bash
# before running this script, the array below must be populated with
# all nodes pub keys that will be part of the route
declare pub_keys=(
03bd5aef25b963cc256bdd009bc8084891e53cd067b781c68786f333e63a186e0f # first hop pub key
03a97a8f6f2bd2293285474a4be48e8d971f333aa3183c95e51d0f704fd42fd92e # next hop's pub key
02258a9aa9463749bf729511af78b1ea339ecdb36b37a6e18a8c8caa895228bfcb # next hop's pub key
026b6cc74185ddc03cf5c57641b1c853dbab5fb2b738883c3891c5b4858f4e68b9 # next hop's pub key
025df45996b60d6f5a834f0963d2c3da6a0f187b7b434dc0cc3af46cf7956c3603 # next hop's pub key
03581cae4671ebfc1d23fe971411216ee004102ab440069409c4748167ba96118e # next hop's pub key
0334c4b3e5bc2c4677974561cc484f50181a5983cc956ceac473fb3f86c11f6299 # next hop's pub key
02b6b8e6b683811f358e9602f8271694951b92dd66ff0841501f2ce9ddcf7bc2fc # next hop's pub key
02e425b0102cf690b8c1bce9d42771a41f615ad5c417247d57d1949b7e8e7ff3a4 # your node's pub key
)
AMOUNT=250000 # value in satoshis to transmit
OUTGOING_CHAN_ID=766999520399654913 # initial channel to transmit from
MAX_FEE=10000 # Max fee, in sats that you're prepared to pay.
####################################################
## the remaining of this script can remain untouched
# Join pub keys into single string at $HOPS
IFS=, eval 'HOPS="${pub_keys[*]}"'
# If an umbrel, use docker, else call lncli directly
LNCLI="lncli"
if uname -a | grep umbrel > /dev/null; then
LNCLI="docker exec -i lnd lncli"
fi
# Arg option: 'build'
build () {
$LNCLI buildroute --amt ${AMOUNT} --hops ${HOPS} --outgoing_chan_id ${OUTGOING_CHAN_ID}
}
# Arg option: 'send'
send () {
INVOICE=$($LNCLI addinvoice --amt=${AMOUNT} --memo="Rebalancing...")
PAYMENT_HASH=$(echo -n $INVOICE | jq -r .r_hash)
PAYMENT_ADDRESS=$(echo -n $INVOICE | jq -r .payment_addr)
ROUTE=$(build)
FEE=$(echo -n $ROUTE | jq .route.total_fees_msat)
# The fee is expressed as a quoted string in msat. A string length of less than 6 indicates a 0 sat fee.
FEE=$([ ${#FEE} -lt 6 ] && echo "0" || echo ${FEE:1:-4})
echo "Route fee is $FEE sats."
if (( FEE > MAX_FEE )); then
echo "Error: $FEE exceeded max fee of $MAX_FEE"
exit 1
fi
echo $ROUTE \
| jq -c "(.route.hops[-1] | .mpp_record) |= {payment_addr:\"${PAYMENT_ADDRESS}\", total_amt_msat: \"${AMOUNT}000\"}" \
| $LNCLI sendtoroute --payment_hash=${PAYMENT_HASH} -
}
# test for availability of tools before use, don't rely on users
# not used to cli dealing with errors down the line
assert_tools () {
err=0
while test $# -gt 0; do
command -v "$1" >/dev/null 2>/dev/null || {
>&2 printf "tool missing: $1\n"
err=$(( $err + 1 ))
}
shift
done
test $err -eq 0 || exit $err
}
# Arg option: '--help'
help () {
cat << EOF
usage: ./igniter.sh [--help] [build] [send]
<command> [<args>]
Open the script and configure values first. Then run
the script with one of the following flags:
build Build the routes for the configured nodes
send Build route and send payment along route
EOF
}
# Run the script
dependecies="cat jq lncli"
#assert_tools ${dependecies}
all_args=("$@")
rest_args_array=("${all_args[@]:1}")
rest_args="${rest_args_array[@]}"
case $1 in
"build" )
build $rest_args
;;
"send" )
send $rest_args
;;
"--help" )
help
;;
* )
help
;;
esac
6. Test our route
./igniter.sh build
7. Send a transaction to yourself by entering the following command:
Make sure all (base)fees are set to 0 or 1 to avoid paying unnecessary fees.
./igniter.sh send
Your node (and all others) will start rebalancing.

8. All channels are now rebalanced and your ring of fire is ready to route 😎

Resources
Last updated
Was this helpful?