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.
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.
Installation
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 https://github.com/Blockstream/liquid/releases/download/liquid.3.14.1.21/liquid-3.14.1.21-x86_64-linux-gnu.tar.gz
$ tar zxf liquid*.tar.gz
$ ln -s `realpath liquid-3.14.1.21` `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-3.14.1.21/bin/liquidd
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:
rpcuser=user
rpcpassword=santa
rpcallowip=0.0.0.0/0
txindex=1
printtoconsole=1
server=1
The Liquid daemon must be able to speak to the Bitcoin daemon, which we configure in /opt/liquid/liquid.conf
:
rpcuser=user
rpcpassword=claus
rpcallowip=0.0.0.0/0
txindex=1
printtoconsole=1
mainchainrpchost=127.0.0.1
mainchainrpcuser=user
mainchainrpcpassword=santa
mainchainrpcport=8332
rpcport=8432
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/bitcoinJan 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/liquidJan 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
3GDctGL32v4Mt8GRqQsjA44aw7o2DVsRV6
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
8954038936ec3d96a283fd7e5336ec17e4ad06876ad2a765ceef31778f70a5b0
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` 0014af097f4f55cc5245a9c71dc5f0d24be01e84b87305fcef878d6cb8bafc8e860ca687ec1ac56ace5e82bda2bd802b94e6a456550c
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 usingvalidateaddress
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?