#wallet #command #liquid #cli-command #lwk #serial #server

bin+lib lwk_cli

Liquid Wallet Kit - Command line interface to interact with the RPC server

8 releases (breaking)

new 0.8.0 Oct 14, 2024
0.7.0 Jul 5, 2024
0.5.1 May 22, 2024
0.4.0 May 3, 2024
0.1.0 Jan 26, 2024

#228 in Magic Beans

Download history 130/week @ 2024-07-03 3/week @ 2024-07-10 4/week @ 2024-07-24 20/week @ 2024-07-31 1/week @ 2024-08-14 2/week @ 2024-08-21 8/week @ 2024-09-11 9/week @ 2024-09-18 15/week @ 2024-09-25 6/week @ 2024-10-02 150/week @ 2024-10-09

181 downloads per month

MIT OR BSD-2-Clause

58KB
1K SLoC

CLI

Building the needed executable requires rust:

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

If you want to enable Jade over serial build with

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

Help shows available commands:

$ lwk_cli --help

Install bash completion with:

$ lwk_cli generate-completion bash | jq -r . | sudo tee /usr/share/bash-completion/completions/lwk_cli

Other shell are available: bash, elvish, fish, powershell, zsh. The destination file path /usr/share/bash-completion/completions/cli may change according to your distro.

Server

Start

$ lwk_cli server start

Or with more logs:

$ RUST_LOG=debug lwk_cli server start

Start the server in background and have logs on file

$ lwk_cli server start 2>debug.log &

Stop

If not in background hit ctrl-c in the terminal where it started or in another shell:

$ lwk_cli server stop

Another way to terminate a server started in background is to type fg to bring the background process in the forground and then hit ctrl-c

Client

Every command requires the server running.

Generate a software signer ("stateless" request)

$ lwk_cli signer generate

is equivalent to:

$ curl --header "Content-Type: application/json" --request POST --data '{"method":"signer_generate","params":[],"id":1,"jsonrpc":"2.0"}' http://localhost:32111 -s

To see RPC data exchanged via the cli commands enable app log tracing eg:

$ RUST_LOG=app=trace cargo run -- wallet balance --wallet ciao
...
2023-11-28T09:36:18.696846Z TRACE app::client: ---> {"method":"balance","params":{"name":"ciao"},"id":2,"jsonrpc":"2.0"}
2023-11-28T09:36:18.697675Z TRACE app::client: <--- {"result":null,"error":{"code":-32008,"message":"Wallet 'ciao' does not exist","data":{"name":"ciao"}},"id":2,"jsonrpc":"2.0"}
{
  "code": -32008,
  "data": {
    "name": "ciao"
  },
  "message": "Wallet 'ciao' does not exist"
}

Load a wallet and request a balance ("stateful" request)

$ lwk_cli wallet load --wallet custody -d "ct(L3jXxwef3fpB7hcrFozcWgHeJCPSAFiZ1Ji2YJMPxceaGvy3PC1q,elwpkh(tpubD6NzVbkrYhZ4Was8nwnZi7eiWUNJq2LFpPSCMQLioUfUtT1e72GkRbmVeRAZc26j5MRUz2hRLsaVHJfs6L7ppNfLUrm9btQTuaEsLrT7D87/*))#lrwadl63"
$ lwk_cli wallet balance --wallet custody

is equivalent to:

$ curl --header "Content-Type: application/json" --request POST --data '{"method":"wallet_load","params":{"descriptor":"ct(L3jXxwef3fpB7hcrFozcWgHeJCPSAFiZ1Ji2YJMPxceaGvy3PC1q,elwpkh(tpubD6NzVbkrYhZ4Was8nwnZi7eiWUNJq2LFpPSCMQLioUfUtT1e72GkRbmVeRAZc26j5MRUz2hRLsaVHJfs6L7ppNfLUrm9btQTuaEsLrT7D87/*))#lrwadl63", "name": "custody"},"id":1,"jsonrpc":"2.0"}' http://localhost:32111 -s

$ curl --header "Content-Type: application/json" --request POST --data '{"method":"balance","params":{"name":"custody"},"id":1,"jsonrpc":"2.0"}' http://localhost:32111 -s | jq .result

Request an address:

$ lwk_cli wallet address --wallet custody
$ lwk_cli wallet address --wallet custody --index 4

An error test case:

$ curl --header "Content-Type: application/json" --request POST --data '{"method":"wallet_load","params":{"desc":"fake"},"id":1,"jsonrpc":"2.0"}' http://localhost:32111 -s | jq
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "Serde JSON Error: missing field `descriptor`",
    "data": null
  }
}

Create a singlesig wallet

First start the server

lwk_cli --network testnet server start
$ MNEMONIC=$(lwk_cli signer generate | jq -r .mnemonic)
$ lwk_cli signer load-software --persist true --mnemonic "$MNEMONIC" --signer s1
$ DESCRIPTOR=$(lwk_cli signer singlesig-desc --signer s1 --descriptor-blinding-key slip77 --kind wpkh | jq -r .descriptor)
$ lwk_cli wallet load --wallet w1 -d "$DESCRIPTOR"
$ lwk_cli wallet address --wallet w1

Send some lbtc to the address

$ lwk_cli wallet balance --wallet w1

Should show a balance

Creating a transaction, signing and broadcasting

You must have a loaded singlesig wallet w1, with the corresponding signer w1 as created in the previous step. Must also have funds in the wallet.

$ UNSIGNED_PSET=$(lwk_cli wallet send --wallet w1 --recipient tlq1qqwe0a3dp3hce866snkll5vq244n47ph5zy2xr330uc8wkrvc0whwsvw4w67xksmfyxwqdyrykp0tsxzsm24mqm994pfy4f6lg:1000:144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49 | jq -r .pset)

Creates an unsigned PSET sending 1000 satoshi of liquid btc (144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49 is the policy asset in testnet) to the address tlq1qqwe0a3dp3hce866snkll5vq244n47ph5zy2xr330uc8wkrvc0whwsvw4w67xksmfyxwqdyrykp0tsxzsm24mqm994pfy4f6lg

Sign the pset

$ SIGNED_PSET=$(lwk_cli signer sign --signer s1 --pset $UNSIGNED_PSET | jq -r .pset)

Broadcast it. Remove --dry-run to effectively broadcast live, otherwise only partial checks on the transactions finalization are made (for example it's not checked inputs are unspent)

$ lwk_cli wallet broadcast --dry-run --wallet w1 --pset $SIGNED_PSET)

Dependencies

~33–47MB
~686K SLoC