Giter Club home page Giter Club logo

lwk's Introduction

Liquid Wallet Kit

LWK logo

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 polishing these bindings and expanding the available options. Additionally, 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 in the demo app or in the working liquid web wallet.
  • 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 functionalities 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: an arrow indicates "depends on" (when dotted the dependency is feature-activated, when blue is a dev-dependency):

Dep tree

(generated with cargo depgraph --workspace-only --dev-deps)

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 committed to continue working on this to have a fully featured LWK working on WASM environments. 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 [email protected]: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 prompt 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.

lwk's People

Contributors

angelix avatar apotdevin avatar dangeross avatar delta1 avatar domegabri avatar ezerfra avatar i5hi avatar jtrivinop avatar leocomandini avatar lvaccaro avatar ok300 avatar rcasatta avatar tohrxyz avatar yusukeshimizu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lwk's Issues

Support for signet

Please add support for signet.

Unfortunately, the frequent "block storms" on testnet affect LN payments, making testnet unreliable.

Error doing a full scan with pending transactions

When I attempt to do a full scan new EsploraClient(...).fullScan(wollet) for a wallet that has an unconfirmed transaction I get the following error "Unexpected error value: "Wollet(JsonFrom(Error("missing field 'block_height'", line: 1, column: 2850)))""

[feature request]:use electrum server for fee rate estimation

The fee rate appears to be a fixed value if not specified, such as send rpc.
I would like to request to use the electrum/electrs blockchain.estimatefee for a fee rate estimate.

Also, it would be nice if it could be considered the confidential transaction discounts.
ElementsProject/elements#1317

Steps to reproduce

My understand is that the fee used in the following commands is a fixed value.

lwk_cli wallet send --wallet w1 --recipient tlq1qqwe0a3dp3hce866snkll5vq244n47ph5zy2xr330uc8wkrvc0whwsvw4w67xksmfyxwqdyrykp0tsxzsm24mqm994pfy4f6lg:1000:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49

Additional Context

As far as I have checked the code, the fee_rate is set to 100.0.

fee_rate: 100.0,

This is a feature that I thought would be nice to have in the implementation to make lwk available in peerswap.
Now, we call directly on electrs' estimate fee.
ElementsProject/peerswap#288

Dependency issue with secp256k1-zkp when linking lwk via git in Cargo.toml

I am trying to test the library and I have a project with this Cargo.toml

[package]
name = "drops"
version = "0.1.0"
edition = "2021"

[dependencies]
lwk_wollet = { git = "https://github.com/Blockstream/lwk.git", package = "lwk_wollet" }

Running cargo build gives the following error:

error: failed to select a version for `secp256k1-zkp-sys`.
    ... required by package `secp256k1-zkp v0.9.1`
    ... which satisfies dependency `secp256k1-zkp = "^0.9.1"` of package `elements v0.22.0`
    ... which satisfies dependency `elements = "^0.22.0"` of package `elements-miniscript v0.2.0`
    ... which satisfies dependency `elements-miniscript = "^0.2"` of package `lwk_wollet v0.1.0 (https://github.com/Blockstream/lwk.git#e53494cf)`
    ... which satisfies git dependency `lwk_wollet` of package `drops v0.1.0 (/home/ishi/operator/dev/wallet/repo/drops)`
versions that meet the requirements `^0.8.0` are: 0.8.1, 0.8.0

the package `secp256k1-zkp-sys` links to the native library `rustsecp256k1zkp_v0_8_0`, but it conflicts with a previous package which links to `rustsecp256k1zkp_v0_8_0` as well:
package `secp256k1-zkp-sys v0.9.0`
    ... which satisfies dependency `secp256k1-zkp-sys = "^0.9.0"` of package `secp256k1-zkp v0.10.0`
    ... which satisfies dependency `secp256k1-zkp = "^0.10.0"` of package `elements v0.24.0`
    ... which satisfies dependency `elements = "^0.24.0"` of package `lwk_wollet v0.1.0 (https://github.com/Blockstream/lwk.git#e53494cf)`
    ... which satisfies git dependency `lwk_wollet` of package `drops v0.1.0 (/home/ishi/operator/dev/wallet/repo/drops)`
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='secp256k1-zkp-sys' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.

failed to select a version for `secp256k1-zkp-sys` which could resolve this conflict

React Native

Not too familiar with wasm but any ideas what would be needed to get this running on react native?

Drain wallet support

There is currently no drain wallet support.

To emulate draining of a wallet I am currently running a "hack" where I loop over the total amount and subtract 1000 sats everytime lwk is not able to provide a valid pset. (I am working with lwk-dart bindings)

  Future<String> buildDrainWalletTx(TransactionBuilder params) async {
    var amount = params.amount;
    while (true) {
      try {
        final pset = await config.liquid.wallet.buildLbtcTx(
          sats: amount,
          outAddress: params.outAddress,
          feeRate: params.fee * 1000,
        );
        return pset;
      } catch (e) {
        if (amount > 0) {
          amount -= 1000;
        } else {
          if (e.toString().contains("InsufficientFunds")) {
            throw "Insufficient funds";
          }
          throw e.toString();
        }
      }
    }
  }
  

In my wallet this kinda works but it is not perfect. There is always some outstanding balance that user cannot spend

IMAGE 2024-05-20 15:59:17

Do you have any solution to drain wallet?

Serde JSON Error: missing field `persist` after updating to cli_0.5.1

After updating to cli_0.5.1 from 0.3.1, LWK has a problem with my state.json.

$ RUST_LOG=debug lwk_cli server start
2024-06-30T20:12:29.427219Z  INFO lwk_cli: logging initialized
2024-06-30T20:12:29.427283Z  INFO lwk_cli: CLI initialized with args: Cli { network: Testnet, addr: None, command: Server(ServerArgs { command: Start { electrum_url: None, esplora_api_url: None, datadir: None, timeout: None, scanning_interval: None } }) }
2024-06-30T20:12:29.430111Z  INFO lwk_app: Creating new app with config: Config { addr: 127.0.0.1:32111, datadir: "/home/user/.lwk", electrum_url: "blockstream.info:465", network: LiquidTestnet, tls: true, validate_domain: true, explorer_url: "https://blockstream.info/liquidtestnet/", esplora_api_url: "https://blockstream.info/liquidtestnet/api/", registry_url: "https://assets-testnet.blockstream.info/", timeout: 90s, scanning_interval: 10s }
2024-06-30T20:12:29.436856Z  INFO lwk_app: Loading previous state, 2 elements
2024-06-30T20:12:29.457736Z DEBUG hyper_util::client::legacy::connect::http: connecting to 127.0.0.1:32111
2024-06-30T20:12:29.458448Z DEBUG hyper_util::client::legacy::connect::http: connected to 127.0.0.1:32111
2024-06-30T20:12:29.461098Z DEBUG lwk_tiny_jrpc: received request - method: Post, url: "/", headers: [Header { field: HeaderField("content-type"), value: "application/json" }, Header { field: HeaderField("content-length"), value: "176" }, Header { field: HeaderField("accept"), value: "*/*" }, Header { field: HeaderField("host"), value: "127.0.0.1:32111" }]
2024-06-30T20:12:29.461277Z DEBUG lwk_app: method: signer_load_software params: Some(Object {"mnemonic": String(""), "name": String("testsigner1")}) 
2024-06-30T20:12:29.461742Z DEBUG hyper_util::client::legacy::pool: pooling idle connection for ("http", 127.0.0.1:32111)
Error: Error re-applying start request
Error Rpc returned an error RpcError { code: -32005, message: "Serde JSON Error: missing field `persist`", data: None }
At line 1 from file /home/user/.lwk/liquid-testnet/state.json
Consider: (a) correct the line (b) remove the line (c) remove the file

Add custom blinding key support

I have used BTCPayServer to receive payments on confidential liquid addresses, the NBXplorer docs describe how it creates blinding keys.

I do have the blinding keys but there is currently no way to set this for a transaction, so I am not able to spend it.

2024-04-23T15:33:48.786803Z  INFO lwk_wollet::clients: [elements]<txid>:0 cannot unblind, ignoring (could be sender messed up with the blinding process)

An alternative way I could spend is using elements-cli createrawtransaction after importing the blinding keys and rescanning the wallet. Unfortunately the hex-output of createrawtransaction is not comptabile with the lwk_cli signer sign command, and I am not able to sign with elements-cli itself since the wallet belongs to a hardware signer.

Check lwk compatibility with confidential transactions discount

Description

Elements version 23.2.2 and later introduce a discount for confidential transactions.
Would it be possible to add a way for users to check if their lwk version supports the confidential transactions discount?

Background

In peerswap, we're looking to implement a feature that adjusts the default fee rate based on whether confidential transactions are supported.
Having a way to verify lwk compatibility would be very helpful for this.

For your reference, I've attached a link to a pull request that addresses this in the context of elements.
ElementsProject/peerswap#304

Unable to get the Jade ID when running on testnet

Using LWK at e53494c on Ubuntu 23.10.

Running with --network mainnet works, but when trying using testnet I get this error:

$ cli signer jade-id
{
  "code": -32013,
  "data": null,
  "message": "Jade Error: Jade Error: Error code: -32003 - message: Network type inconsistent with prior usage"
}

PSET to TX and back

In a remote signing env where the PSET is created on the server and sent to the client for signing, the flow I have in mind is:

  1. Create PSET
  2. Extract TX from the PSET
  3. Send TX string to client
  4. Client constructs PSET and signs it
  5. Client extracts TX and sends the signed TX string back to us
  6. We broadcast the TX

Now, the part I'm missing is how to go from a TX string to a PSET that can then be signed.

How could I go about that? Would this be the correct flow for remote signing?

Missing transactions after wallet refresh

I created a wallet and sent funds to the first address it generated but when refreshing the wallet it doesn't find the transactions and shows the wallet as empty.

Here is the address and the transaction.

The wallet was generated with this mnemonic (It's empty now):
spirit quick body unveil aim craft swear dizzy sentence season only grab

Note:

  • I'm using the new waterfall api for refreshing a wallets state.
  • When I import into Green wallet all the funds correctly appear

Support for CT Descriptor wallet to also handle unblinded outputs

Currently a CT Descriptor Wallet only recognizes blinded outputs. If the user of the wallet shares a confidential address and the sender does not blind the outputs and instead sends to the unblinded address, the wallet does not detect the transaction.

It would be nice if the CT Descriptor Wallet can also recognize and handle unblinded outputs.

C# bindings

Since you use uniffi for bindings, C# should be relatively easy to add support for.

[feature request] Option to bypass signature "grinding"

I'm using LWK to generate test vectors for an embedded Liquid app running on the Ledger Nano S platform. Unfortunately, the vendor-supplied SDK for this platform does not provide control over nonce (entropy) of ECDSA signature function. Thus, to make test vectors with reproducible signatures, I have to patch LWK manually changing secp.sign_ecdsa_low_r() to secp.sign_ecdsa().

It would be nice if the external API of LWK had an optional flag allowing bypassing signature grinding.

Here is the line I'm modifying:

let sig = self.secp.sign_ecdsa_low_r(&msg, &private_key.inner);

Typo in codebase

I noticed there are several instances where wollet instead of wallet is used. Is this something you are interested in fixing? If so I could potentially submit a PR for this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.