Integrating Blockstream’s Liquid payments on SideShift AI

Blockstream’s Liquid product is a fork of Bitcoin that replaces the consensus model from proof-of-work to a federated consensus model. Most users are familiar with the federated consensus model from other payment networks such as Ripple.

Bitfinex and BitMEX were announced by Blockstream as partnering exchanges, but I was unable to find deposit/withdrawal of L-BTC on either exchange. Perhaps SideShift AI will be the first to integrate Liquid.

Live demonstration of a Shift of BTC from Bitcoin Lightning to Liquid.

Instance specification

I deploy a Ubuntu 18.04 instance on Amazon AWS with these modest specs:

  • t2.smal (1 vCPU, 2 GB RAM)
  • OS volume: 20 GB SSD
  • Data volume: 250 GB SSD

The reason for the low specs is that Liquid is new and won’t have to deal with a large mempool or transaction throughput.

I habitually use a separate volume for the node data, which includes configuration file, blockchain data, wallet data. This allows me to easily switch over to a new machine if the OS should suffer a catastrophic event.


Liquid requires both a liquidd node and a bitcoind node. This is because Liquid is a sidechain that’s able to receive BTC from the Bitcoin chain and return BTC to the Bitcoin chain.

Over at the releases page on the Liquid Github I find the latest release, v3.14.1.21, download and extract it:

$ wget
$ tar zxf liquid*.tar.gz
$ ln -s `realpath liquid-` `realpath liquid`
$ pushd /usr/local/bin
$ sudo ln -s /home/ubuntu/liquid/bin/* .

I’ve now created symbolic links like this:

/usr/local/bin/liquidd -> /home/ubuntu/liquid/bin/liquidd -> /home/ubuntu/liquid-

This symlink chain makes it convenient to upgrade Liquid in the future. I just need to replace the link to /home/ubuntu/liquid.

I replace this procedure for the latest version of Bitcoin Core, such that /usr/local/bin/bitcoind links to /home/ubuntu/bitcoin-0.17.0/bin.

For both bitcoind and liquidd to start automatically, I create two systemd unit files; bitcoind.servivce and liquidd.service.

You can see in the systemd unit files that bitcoind and liquidd have their data directories set to /opt/bitcoin and /opt/liquid respectively. The /opt directory is the data volume I described previously.

Configuration files

The Bitcoin configuration file, /opt/bitcoin/bitcoin.conf is quite straight forward:


The Liquid daemon must be able to speak to the Bitcoin daemon, which we configure in /opt/liquid/liquid.conf:


Liquid is now able to speak to Bitcoin over RPC.

Starting the instances

I first enable and start the bitcoind system service:

$ sudo systemctl enable bitcoind
$ sudo systemctl start bitcoind
$ sudo systemctl status bitcoind
● bitcoind.service - Bitcoin Daemon
Loaded: loaded (/etc/systemd/system/bitcoind.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2018-11-12 01:05:18 UTC; 1 day ago
Main PID: 1624 (bitcoind)
Tasks: 13 (limit: 2362)
CGroup: /system.slice/bitcoind.service
└─1624 /usr/local/bin/bitcoind -datadir=/opt/bitcoin
Jan 17 20:49:46 sideshift-liquid bitcoind[1624]: 2019-01-17T20:49:46Z Pre-allocating up to position 0x1000000 in blk01498.dat
Jan 17 20:49:46 sideshift-liquid bitcoind[1624]: 2019-01-17T20:49:46Z Pre-allocating up to position 0x100000 in rev01498.dat

and for the liquid service:

$ sudo systemctl enable liquidd
$ sudo systemctl start liquidd
$ sudo systemctl status liquidd
● liquidd.service - Liquid Daemon
Loaded: loaded (/etc/systemd/system/liquidd.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2018-11-12 01:07:30 UTC; 1 day ago
Main PID: 1766 (liquidd)
Tasks: 14 (limit: 2362)
CGroup: /system.slice/liquidd.service
└─1766 /usr/local/bin/liquidd -datadir=/opt/liquid
Jan 17 22:01:36 sideshift-liquid liquidd[1766]: 2019-01-17 22:01:36 UpdateTip: new best=f3a5b642f9e0347642c3a4412d4f7425f1e97fd3e3a5600e1ca45d38a92773d5 height=142622 version=0x20000000 log2_work=17.121

Obtaining some L-BTC

The native currency of the Liquid network is L-BTC, which means BTC that is stored in the Liquid sidechain. We could have a friend send us some L-BTC, buy it on an exchange, or send from the Bitcoin network using the peg-in process. The latter is obviously cooler.

To make my life a little easier, create these two aliases in my shell:

alias btc="bitcoin-cli -datadir=/opt/bitcoin"
alias lq="liquid-cli -datadir=/opt/liquid"

I generate a new Bitcoin address:

$ btc getnewaddress

And I send it 0.02669942 BTC (around $100). Storing the funds using a Bitcoin Core wallet will make this process much simpler.

We then obtain a peg-in address for Liquid:

$ lq getpeginaddress
"mainchain_address": "31oQLrR1qeGSdJxFMeTVuXkqxjd9gJ1E6s",
"claim_script": "0014af097f4f55cc5245a9c71dc5f0d24be01e84b873"

And send the funds to the peg-in address:

$ btc sendtoaddress 31oQLrR1qeGSdJxFMeTVuXkqxjd9gJ1E6s `btc getbalance` "" "" true

This transaction is the peg-in transaction. We’ll need its raw transaction data to claim the peg-in transaction later:

$ btc getrawtransaction 8954038936ec3d96a283fd7e5336ec17e4ad06876ad2a765ceef31778f70a5b0 > tx.txt

And the transaction proof

btc gettxoutproof '["8954038936ec3d96a283fd7e5336ec17e4ad06876ad2a765ceef31778f70a5b0"]' > proof.txt

There’s quite a few strings to deal with now, and we’ll need to use them when we claim the peg-in transaction. But there’s catch! We’ll need to wait for 102 confirmations (~17 hours) to be able to claim the peg-in.

| Name | Value |
| Peg-in address | 31oQLrR1qeGSdJxFMeTVuXkqxjd9gJ1E6s |
| Claim-script | 0014af097f4f55cc5245a9c71dc5f0d24be01e84b873 |
| Peg-in tx hash | 8954038936ec3d96a283fd7e5336ec17e4ad06876... |
| Peg-in tx proof| Stored in proof.txt |
| Peg-in tx raw | Stored in tx.txt |

102 confirmations later

We can now claim the peg-in transaction.

$ lq claimpegin `cat tx.txt` `cat proof.txt` 0014af097f4f55cc5245a9c71dc5f0d24be01e84b873

After a few minutes we can verify that the L-BTC was received.

$ lq getbalance
"bitcoin": 0.02669942

Experienced bitcoind users will notice that getbalance returns key-values instead of just a number. This is because Liquid supports issuing custom tokens, like you’re probably used to with ERC20s. A major difference is that Liquid uses a technology called Confidential Assets, which provides privacy.

You can read more about Confidential Assets in its whitepaper.

Integrating sending/receiving payments

SideShift AI will support only the native L-BTC token until some interesting assets become available on the Liquid network. Perhaps we should issue our SAI token as an asset on Liquid?

Integration work for L-BTC is identical to that of Bitcoin:

Receiving funds

for every new block with at least 1 confirmation
for every transaction in that block
for every output in that transaction
- Was it sent to a SideShift AI deposit address?
- Credit the user unless it has previously been credited

Sending funds

Use the sendtoaddress RPC call, or sendtomany if using batching.

Notable differences from Bitcoin

  • getbalance RPC call returns a hashmap (currency->balance)
  • getnewaddress RPC call returns a bech32 address. Can be converted to old-school using validateaddress RPC call.

Closing remarks

Integrating Liquid and pegging in was easier than expected and easily manageable for a developer experienced with Bitcoin. I’m curious to see how integrating Confidential Assets will differ.

SideShift AI is in its TEST PILOT STAGE. Want to become a TEST PILOT?