Skip to content

Blockstream/lwk

Repository files navigation

Liquid Wallet Kit

NOTE: LWK is in public beta and still undergoing significant development. Use it at your own risk.

What is Liquid Wallet Kit (LWK)?

LWK is a collection of Rust crates for Liquid Wallets. Its goal is to provide all the necessary building blocks for Liquid wallet development to enable a broad range of use cases on Liquid.

By not following a monolithic approach but instead providing a group of function-specific libraries, LWK allows us to offer a modular, flexible and ergonomic toolset for Liquid development. This design lets application developers pick only what they need and focus on the relevant aspects of their use cases.

We want LWK to be a reference tool driven both by Blockstream and Liquid participants that helps make Liquid integration frictionless, define ecosystem standards and leverage advanced Liquid capabilities such as covenants or swaps.

While LWK is Rust native, we provide bindings for Python, Kotlin and Swift using Mozilla UniFFI and we provide preliminary support for WASM. We will continue polishinhg these bindings and expanding the available options. Aditionally, the Bull Bitcoin team has developed Dart/Flutter bindings.

Main Features

  • Watch-Only wallet support: using Liquid descriptors, better known as CT descriptors.
  • PSET based: transactions are shared and processed using the Partially Signed Elements Transaction format.
  • Electrum and Esplora backends: no need to run and sync a full Liquid node or rely on closed source servers.
  • Asset issuance, reissuance and burn support: manage the lifecycle of your Issued Assets with a lightweight client.
  • Generic multisig wallets: create a wallet controlled by any combination of hardware or software signers, with a user specified quorum.
  • Hardware signer support: receive, issue, reissue and burn L-BTC and Issued Assets with your hardware signer, using singlesig or multisig wallets (currently Jade only, with more coming soon).
  • Native bindings PoC support for Python, Kotlin and Swift, with many other language available soon using uniffi
  • WASM preliminary support with lwk_wasm crate, see it live.
  • JSON-RPC Server support: all functions are exposed via JSON-RPC Server, making it easier to build your own frontend, GUI, or integration.

LWK Structure

LWK funtionalities are split into different component crates that might be useful independently.

For instance, mobile app devs might be interested mainly in lwk_bindings, lwk_wollet and lwk_signer. While backend developers might want to directly use lwk_cli in their systems.

Internal crate dependencies are shown in this diagram, where an arrow indicates "depends on":

  graph TD;
      cli-->app;
      cli-->rpc_model;

      app-->common;
      app-->wollet;
      app-->signer;
      app-->tiny_jrpc;
      app-->rpc_model;

      jade-->common;

      signer-->common;
      signer-->jade;

      wollet-->common;
      
      bindings-->signer;
      bindings-->wollet;
      bindings-->test_util;

      wasm-->signer;
      wasm-->wollet;

      test_util-->containers

Getting started with LWK Development

Rust

Build

You can build all crates with:

cargo build

Or you can build a single crate with:

cargo build -p lwk_wollet

Rust Examples

Python

Install from Pypi

pip install lwk

Build Python wheel

First, create a virtual env, skip the step if you already created it.

cd lwk/lwk_bindings
virtualenv venv
source venv/bin/activate
pip install maturin maturin[patchelf] uniffi-bindgen

Then build the wheel

cd lwk/lwk_bindings
maturin develop

Try it (note there is still an issue in how we import the package when using the wheel):

import lwk
str(lwk.Network.mainnet())

Python Examples

Kotlin

Build

This will build the bindings library in debug mode and generate the kotlin file

just kotlin

Create android bindings library libs, 4 architectures in release mode

just android

Kotlin Examples

Swift

Swift Examples

WASM

We currently provide preliminary support but are commited to continue working on this to have a fully featured LWK working on WASM enviroments. See these instructions to try out LWK on WASM

See what LWK is capable of by using the command line tool (LWK_CLI)

All LWK functions are exposed via a local JSON-RPC server that communicates with a CLI tool so you can see LWK in action.

This JSON-RPC Server also makes it easier to build your own frontend, GUI, or integration.

If you want to see an overview of LWK and a demo with the CLI tool check out this video

Installing LWK_CLI from crates.io

$ cargo install lwk_cli 

or if you want to connect Jade over serial:

$ cargo install lwk_cli --features-serial 

Building LWK_CLI from source

First you need rust, our MSRV is 1.75.0 then you can build from source:

$ git clone git@github.com:Blockstream/lwk.git
$ cd lwk
$ cargo install --path ./lwk_cli/ 

Or

$ cargo install --path ./lwk_cli/ --features serial

To enable connection with Jade over serial.

Using LWK_CLI

Help will show available commands:

$ lwk_cli --help

Start the rpc server (default in Liquid Testnet) and put it in background

$ lwk_cli server start

Every command requires the server running so open a new shell to run the client.

Create new BIP39 mnemonic for a software signer

$ lwk_cli signer generate

Load a software signer named sw from a given BIP39 mnemonic

$ lwk_cli signer load-software --signer sw --persist false --mnemonic "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

Create a p2wpkh wallet named ss (install jq or extract the descriptor manually)

$ DESC=$(lwk_cli signer singlesig-desc -signer sw --descriptor-blinding-key slip77 --kind wpkh | jq -r .descriptor)
$ lwk_cli wallet load --wallet ss -d $DESC

Get the wallet balance

$ lwk_cli wallet balance -w ss

If you have a Jade, you can plug it in and use it to create a wallet and sign its transactions.

Probe connected Jades and promt user to unlock it to get identifiers needed to load Jade on LWK

$ lwk_cli signer jade-id

Load Jade using returned ID

$ lwk_cli signer load-jade --signer <SET_A_NAME_FOR_THIS_JADE> --id <ID>

Get xpub from loaded Jade

$ lwk_cli signer xpub --signer <NAME_OF_THIS_JADE> --kind <bip84, bip49 or bip87>

When you're done, stop the rpc server.

$ lwk_cli server stop

Tests

Run unit tests:

cargo test --lib

End-to-end tests need some local servers:

./context/download_bins.sh # needed once unless server binaries changes
. .envrc  # not needed if you use direnv and you executed `direnv allow`

And also the following docker images:

docker pull xenoky/local-jade-emulator:1.0.27
docker pull tulipan81/blind_pin_server:v0.0.7

Note: Failed test executions can leave docker containers running. To stop all running containers run:

docker stop $(docker ps -a -q)

To run end-to-end tests:

cargo test

To see log outputs use RUST_LOG for example

RUST_LOG=info cargo test -- test_name
RUST_LOG=jade=debug cargo test -- test_name  # filter only on specific module

Test with a physical Jade

Tests using Jade over serial (via USB cable) need an additional dependency:

apt install -y libudev-dev

These serial tests cannot be executed in parallel, so we need the --test-threads 1 flag.

cargo test -p lwk_jade --features serial -- serial --include-ignored --test-threads 1
cargo test -p lwk_wollet --features serial -- serial --include-ignored --test-threads 1

Docs

To generate documentation you can use

RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --open

Nix

We provide a flake for a dev environment and for running the lwk_cli. If you use direnv and allow the .envrc the dev environment is automatically loaded as soon as you enter the directory, otherwise you can run:

nix develop

To run lwk_cli on nix-enabled system:

nix run github:blockstream/lwk

History

BEWallet was originally an Elements/Liquid wallet library written in Rust to develop prototypes and experiments.

BEWallet was based on Blockstream's GDK. Essentially some GDK Rust pieces were moved to this project.

This was used as the starting point for the Liquid Wallet Kit project. Parts that were not necessary have been dropped, many things have been polished, and new features have been added.

The codebase has been entirely re-written, and now it has almost no similarity with the original code.