diff --git a/README.md b/README.md
index ab0c3ea..87119ef 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,45 @@
-# legend-regtest-enviroment
-Useful and easy docker LNbits regtest enviroment.
+# setup
+clone it into your lnbits-legend repository
+```console
+mkdir ~/repos/lnbits-legend/docker
+git clone git@github.com:lnbits/legend-regtest-enviroment.git ~/repos/lnbits-legend/docker
-Will spin up regtest:
+```
+# usage
+```console
+cd ~/repos/lnbits-legend/docker
+source docker-scripts.sh
-* lnbits
-* bitcoin-core
-* lnd
-* clightning
-* electrs
-* mempool
-* boltz
+# start docker-compose with logs
+lnbits-regtest-start-log
+# start docker-compose in background
+lnbits-regtest-start
-Just place the docker folder in your lnbits-legend install. To run use these instructions
+# errors on startup are normal! wait at least 60 seconds
+# for all services to come up before you start initializing
+sleep 60
+
+# initialize blockchain,
+# fund lightning wallets
+# connect peers
+# create channels
+# balance channels
+lnbits-regtest-init
+
+# use bitcoin core, mine a block
+bitcoin-cli-sim -generate 1
+
+# use c-lightning nodes
+lightning-cli-sim 1 newaddr # use node 1
+lightning-cli-sim 2 getinfo # use node 2
+lightning-cli-sim 3 getinfo | jq -r '.bech32' # use node 3
+
+# use lnd nodes
+lncli-sim 1 newaddr p2wsh
+lncli-sim 2 listpeers
+```
+
+# lnbits debug log
+```console
+docker logs lnbits-legend-lnbits-1 -f
+```
diff --git a/data/boltz/boltz.conf b/data/boltz/boltz.conf
new file mode 100644
index 0000000..c9e9d6d
--- /dev/null
+++ b/data/boltz/boltz.conf
@@ -0,0 +1,34 @@
+[api]
+host = "boltz"
+port = 9_001
+
+[[pairs]]
+base = "BTC"
+quote = "BTC"
+rate = 1
+fee = 0.5
+timeoutDelta = 1_440
+
+[[currencies]]
+symbol = "BTC"
+network = "bitcoinRegtest"
+minWalletBalance = 10_000_000
+minChannelBalance = 10_000_000
+maxSwapAmount = 4_294_967
+minSwapAmount = 10_000
+maxZeroConfAmount = 10_000_000
+
+[currencies.chain]
+mempoolSpace = "http://mempool-web:8080/api"
+host = "bitcoind"
+zmqpubrawtx = "tcp://bitcoind:29000"
+zmqpubrawblock = "tcp://bitcoind:29001"
+port = 18_443
+user = "lnbits"
+password = "lnbits"
+
+[currencies.lnd]
+host = "lnd-1"
+port = 10_009
+certpath = "/data/lnd/tls.cert"
+macaroonpath = "/data/lnd/data/chain/bitcoin/regtest/admin.macaroon"
diff --git a/data/electrs/config.toml b/data/electrs/config.toml
new file mode 100644
index 0000000..962fdae
--- /dev/null
+++ b/data/electrs/config.toml
@@ -0,0 +1,3 @@
+network="regtest"
+auth="lnbits:lnbits"
+wait_duration="45s"
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..65a0c8b
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,153 @@
+version: "3.7"
+services:
+ lnbits:
+ hostname: lnbits
+ image: lnbitsdocker/lnbits-legend
+ restart: on-failure
+ user: "0:0"
+ entrypoint: "sh -c 'sleep 30; uvicorn lnbits.__main__:app --port 5000 --host lnbits --reload'"
+ environment:
+ HOST: lnbits
+ LNBITS_BACKEND_WALLET_CLASS: "LndRestWallet"
+ LNBITS_DATA_FOLDER: "./data"
+ LND_REST_ENDPOINT: "https://lnd-2:8081/"
+ LND_REST_CERT: "./lnd/tls.cert"
+ LND_REST_MACAROON: "./lnd/data/chain/bitcoin/regtest/admin.macaroon"
+ ports:
+ - 5000:5000
+ volumes:
+ - ../lnbits:/app/lnbits
+ - lnbits-data:/app/data
+ - ./data/lnd-2:/app/lnd:uid=1000,gid=1000
+
+ boltz:
+ hostname: boltz
+ image: boltz/backend
+ entrypoint: "sh -c 'sleep 40; /boltz-backend/bin/boltzd'"
+ ports:
+ - 9000:9000
+ - 9001:9001
+ volumes:
+ - ./data/lnd-1:/data/lnd/
+ - ./data/boltz/:/root/.boltz/
+
+ bitcoind:
+ hostname: bitcoind
+ image: boltz/bitcoin-core:22.0
+ command: "-regtest -fallbackfee=0.00000253 -zmqpubrawtx=tcp://0.0.0.0:29000 -zmqpubrawblock=tcp://0.0.0.0:29001 -txindex -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0 -rpcuser=lnbits -rpcpassword=lnbits"
+ expose:
+ - 29000
+ - 29001
+ - 18443
+ - 18444
+
+ clightning-1:
+ hostname: clightning-1
+ image: michael1011/cln:latest
+ entrypoint: "sh -c 'sleep 15 && lightningd --network regtest --bind-addr=0.0.0.0:9735 --bitcoin-rpcconnect=bitcoind --bitcoin-rpcport=18443 --bitcoin-rpcuser=lnbits --bitcoin-rpcpassword=lnbits'"
+ expose:
+ - 9735
+ volumes:
+ - ./data/clightning-1:/root/.lightning/
+
+ clightning-2:
+ hostname: clightning-2
+ image: michael1011/cln:latest
+ entrypoint: "sh -c 'sleep 15 && lightningd --network regtest --bind-addr=0.0.0.0:9735 --bitcoin-rpcconnect=bitcoind --bitcoin-rpcport=18443 --bitcoin-rpcuser=lnbits --bitcoin-rpcpassword=lnbits'"
+ expose:
+ - 9735
+ volumes:
+ - ./data/clightning-2:/root/.lightning/
+
+ clightning-3:
+ hostname: clightning-3
+ image: michael1011/cln:latest
+ entrypoint: "sh -c 'sleep 15 && lightningd --network regtest --bind-addr=0.0.0.0:9735 --bitcoin-rpcconnect=bitcoind --bitcoin-rpcport=18443 --bitcoin-rpcuser=lnbits --bitcoin-rpcpassword=lnbits'"
+ expose:
+ - 9735
+ volumes:
+ - ./data/clightning-3:/root/.lightnind/
+
+ lnd-1:
+ hostname: lnd-1
+ depends_on:
+ - bitcoind
+ image: boltz/lnd:0.14.2-beta
+ restart: on-failure
+ entrypoint: "sh -c 'sleep 20; lnd --listen=lnd-1:9735 --rpclisten=lnd-1:10009 --restlisten=lnd-1:8081 --bitcoin.active --bitcoin.regtest --bitcoin.node=bitcoind --bitcoind.rpchost=bitcoind --bitcoind.zmqpubrawtx=bitcoind:29000 --bitcoind.zmqpubrawblock=bitcoind:29001 --bitcoind.rpcuser=lnbits --bitcoind.rpcpass=lnbits --noseedbackup --protocol.wumbo-channels'"
+ expose:
+ - 8081
+ - 9735
+ - 10009
+ volumes:
+ - ./data/lnd-1:/root/.lnd/
+
+ lnd-2:
+ hostname: lnd-2
+ depends_on:
+ - bitcoind
+ image: boltz/lnd:0.14.2-beta
+ restart: on-failure
+ entrypoint: "sh -c 'sleep 20; lnd --listen=lnd-2:9735 --rpclisten=lnd-2:10009 --restlisten=lnd-2:8081 --bitcoin.active --bitcoin.regtest --bitcoin.node=bitcoind --bitcoind.rpchost=bitcoind --bitcoind.zmqpubrawtx=bitcoind:29000 --bitcoind.zmqpubrawblock=bitcoind:29001 --bitcoind.rpcuser=lnbits --bitcoind.rpcpass=lnbits --noseedbackup --protocol.wumbo-channels'"
+ expose:
+ - 8081
+ - 9735
+ - 10009
+ volumes:
+ - ./data/lnd-2:/root/.lnd/
+
+ electrs:
+ depends_on:
+ - bitcoind
+ hostname: electrs
+ image: getumbrel/electrs:latest
+ environment:
+ ELECTRS_ELECTRUM_RPC_ADDR: "electrs:50001"
+ ELECTRS_DAEMON_RPC_ADDR: "bitcoind:18443"
+ ELECTRS_DAEMON_P2P_ADDR: "bitcoind:18444"
+ entrypoint: "sh -c 'sleep 15 && electrs'"
+ ports:
+ - 50001:50001
+ volumes:
+ - ./data/electrs/:/data/.electrs/
+
+ mempool-web:
+ restart: on-failure
+ environment:
+ FRONTEND_HTTP_PORT: "8080"
+ BACKEND_MAINNET_HTTP_HOST: "mempool-api"
+ image: mempool/frontend:latest
+ ports:
+ - 8080:8080
+
+ mempool-api:
+ depends_on:
+ - electrs
+ environment:
+ MEMPOOL_BACKEND: "electrum"
+ ELECTRUM_HOST: electrs
+ ELECTRUM_PORT: "50001"
+ ELECTRUM_TLS_ENABLED: "false"
+ CORE_RPC_HOST: bitcoind
+ CORE_RPC_PORT: "18443"
+ CORE_RPC_USERNAME: "lnbits"
+ CORE_RPC_PASSWORD: "lnbits"
+ DATABASE_ENABLED: "true"
+ DATABASE_HOST: "mempool-db"
+ DATABASE_DATABASE: "mempool"
+ DATABASE_USERNAME: "mempool"
+ DATABASE_PASSWORD: "mempool"
+ STATISTICS_ENABLED: "true"
+ image: mempool/backend:latest
+ restart: on-failure
+
+ mempool-db:
+ environment:
+ MYSQL_DATABASE: "mempool"
+ MYSQL_USER: "mempool"
+ MYSQL_PASSWORD: "mempool"
+ MYSQL_ROOT_PASSWORD: "admin"
+ image: mariadb:10.5.8
+
+volumes:
+ lnbits-data:
diff --git a/docker-scripts.sh b/docker-scripts.sh
new file mode 100644
index 0000000..0826935
--- /dev/null
+++ b/docker-scripts.sh
@@ -0,0 +1,142 @@
+#!/bin/sh
+export COMPOSE_PROJECT_NAME=lnbits-legend
+
+bitcoin-cli-sim(){
+ docker exec lnbits-legend-bitcoind-1 bitcoin-cli -rpcuser=lnbits -rpcpassword=lnbits -regtest $@
+}
+
+# args(i, cmd)
+lightning-cli-sim() {
+ i=$1
+ shift # shift first argument so we can use $@
+ docker exec lnbits-legend-clightning-$i-1 lightning-cli --network regtest $@
+}
+
+# args(i, cmd)
+lncli-sim() {
+ i=$1
+ shift # shift first argument so we can use $@
+ docker exec lnbits-legend-lnd-$i-1 lncli --network regtest --rpcserver=lnd-$i:10009 $@
+}
+
+# args(i)
+fund_clightning_node() {
+ address=$(lightning-cli-sim $1 newaddr | jq -r .bech32)
+ echo "funding: $address on clightning-node: $1"
+ bitcoin-cli-sim -named sendtoaddress address=$address amount=10 fee_rate=100 > /dev/null
+}
+
+# args(i)
+fund_lnd_node() {
+ address=$(lncli-sim $1 newaddress p2wkh | jq -r .address)
+ echo "funding: $address on lnd-node: $1"
+ bitcoin-cli-sim -named sendtoaddress address=$address amount=10 fee_rate=100 > /dev/null
+}
+
+# args(i, j)
+connect_clightning_node() {
+ pubkey=$(lightning-cli-sim $2 getinfo | jq -r '.id')
+ lightning-cli-sim $1 connect $pubkey@lnbits-legend-clightning-$2-1
+}
+
+lnbits-regtest-start(){
+ lnbits-regtest-stop
+ docker compose up -d --remove-orphans
+}
+
+lnbits-regtest-start-log(){
+ lnbits-regtest-stop
+ docker compose up --remove-orphans
+}
+
+lnbits-regtest-stop(){
+ docker compose down --volumes
+ # clean up lightning node data
+ sudo rm -rf ./data/clightning-1 ./data/clightning-2 ./data/clightning-3 ./data/lnd-1 ./data/lnd-2 ./data/boltz/boltz.db
+ # recreate lightning node data folders preventing permission errors
+ mkdir ./data/clightning-1 ./data/clightning-2 ./data/clightning-3 ./data/lnd-1 ./data/lnd-2
+}
+
+lnbits-regtest-restart(){
+ lnbits-regtest-stop
+ lnbits-regtest-start
+}
+
+lnbits-regtest-init(){
+ echo "init_bitcoin_wallet..."
+ bitcoin-cli-sim createwallet lnbits || bitcoin-cli-sim loadwallet lnbits echo "mining 150 blocks..."
+ bitcoin-cli-sim -generate 150 > /dev/null
+
+ # create 10 UTXOs for each node
+ for i in 0 1 2 3 4 5 6 7 8 9; do
+ fund_clightning_node 1
+ fund_clightning_node 2
+ fund_clightning_node 3
+ fund_lnd_node 1
+ fund_lnd_node 2
+ done
+
+ echo "mining 5 blocks... and waiting for the nodes to catch up"
+ bitcoin-cli-sim -generate 5 > /dev/null
+ wait-for-lnd-sync 1
+ wait-for-lnd-sync 2
+
+ channel_size=16000000 # 0.016 btc
+ balance_size_msat=7000000000 # 0.07 btc
+
+ # open channels 1 -> 2, 2 -> 3, 3 -> 1
+ connect_clightning_node 1 3
+ lightning-cli-sim 1 fundchannel -k id=$(connect_clightning_node 1 2 | jq -r '.id') amount=$channel_size push_msat=$balance_size_msat
+ connect_clightning_node 2 1
+ lightning-cli-sim 2 fundchannel -k id=$(connect_clightning_node 2 3 | jq -r '.id') amount=$channel_size push_msat=$balance_size_msat
+ connect_clightning_node 3 2
+ lightning-cli-sim 3 fundchannel -k id=$(connect_clightning_node 3 1 | jq -r '.id') amount=$channel_size push_msat=$balance_size_msat
+
+ # lnd node for boltz
+ lncli-sim 1 connect $(lightning-cli-sim 1 getinfo | jq -r '.id')@lnbits-legend-clightning-1-1
+ lncli-sim 1 openchannel $(lncli-sim 1 listpeers | jq -r '.peers[0].pub_key') $channel_size 8000000
+
+ # lnd doesnt like more than 1 pending channel?
+ bitcoin-cli-sim -generate 10 > /dev/null
+ echo "waiting for lnd to catch up..."
+ wait-for-lnd-channel 1
+
+ # fund lnbits lnd channel
+ lncli-sim 1 connect $(lncli-sim 2 getinfo | jq -r '.identity_pubkey')@lnbits-legend-lnd-2-1
+ lncli-sim 1 openchannel $(lncli-sim 1 listpeers | jq -r '.peers[1].pub_key') $channel_size 8000000
+
+ bitcoin-cli-sim -generate 10 > /dev/null
+ echo "waiting for lnd to catch up..."
+ wait-for-lnd-channel 1
+
+
+ # lnd node for lnbits
+ lncli-sim 2 connect $(lightning-cli-sim 1 getinfo | jq -r '.id')@lnbits-legend-clightning-1-1
+ lncli-sim 2 openchannel $(lncli-sim 2 listpeers | jq -r '.peers[0].pub_key') $channel_size 8000000
+
+ echo "waiting for lnd to catch up..."
+ bitcoin-cli-sim -generate 10 > /dev/null
+ wait-for-lnd-channel 2
+
+ # TODO: eclair nodes?
+}
+
+wait-for-lnd-channel(){
+ while true; do
+ pending=$(lncli-sim $1 pendingchannels | jq -r '.pending_open_channels | length')
+ if [[ "$pending" == "0" ]]; then
+ break
+ fi
+ sleep 1
+ done
+}
+
+wait-for-lnd-sync(){
+ while true; do
+ if [[ "$(lncli-sim $1 getinfo 2>&1 | jq -r '.synced_to_chain')" == "true" ]]; then
+ break
+ fi
+ sleep 1
+ done
+ sleep 5
+}
diff --git a/docker/README.md b/docker/README.md
deleted file mode 100644
index b1b7161..0000000
--- a/docker/README.md
+++ /dev/null
@@ -1 +0,0 @@
-init