#wallet #lwk #ct #tx-builder #wollet #watch-only

lwk_wollet

Liquid Wallet Kit - Watch-only wallet based on CT Descriptors

14 breaking releases

0.16.0 Mar 23, 2026
0.14.0 Jan 20, 2026
0.13.0 Dec 11, 2025
0.12.0 Sep 24, 2025
0.3.0 Mar 20, 2024

#1 in #tx-builder

Download history 187/week @ 2025-12-24 208/week @ 2025-12-31 257/week @ 2026-01-07 168/week @ 2026-01-14 237/week @ 2026-01-21 255/week @ 2026-01-28 345/week @ 2026-02-04 364/week @ 2026-02-11 349/week @ 2026-02-18 530/week @ 2026-02-25 506/week @ 2026-03-04 334/week @ 2026-03-11 469/week @ 2026-03-18 336/week @ 2026-03-25 281/week @ 2026-04-01 303/week @ 2026-04-08

1,441 downloads per month
Used in 7 crates (6 directly)

MIT OR BSD-2-Clause

660KB
14K SLoC

LWK is a collection of libraries for Liquid wallets. lwk_wollet is the library for Watch-Only Wallets, the wollet spelling is not a typo but highlights the fact it is Watch-Only.

A Wollet is defined by a CT descriptor, which consists in a Bitcoin descriptor plus the descriptor blinding key. More precisely a subset of descriptors are supported, everything parsed by WolletDescriptor. Every method on the Wollet will operate on local data, without network calls. The wallet data is updated via the [Wollet::apply_update()] method.

With a wallet you can:

  • Generate addresses via [Wollet::address()].
  • Pass it to a blockchain backend (ElectrumClient, blocking::EsploraClient) to retrieve wallet history via the [blocking::BlockchainBackend::full_scan()] trait. Or asyncronously via the [asyncr::EsploraClient::full_scan()] method. The convenience method [full_scan_with_electrum_client()] is also provided.
  • Create transactions, inclunding issuances, reissuances and burn via the TxBuilder.
  • Analyze a partially signed transaction with respect to the wallet via [Wollet::get_details()].

Examples

Generate an address

let desc = "ct(slip77(ab5824f4477b4ebb00a132adfd8eb0b7935cf24f6ac151add5d1913db374ce92),elwpkh([759db348/84'/1'/0']tpubDCRMaF33e44pcJj534LXVhFbHibPbJ5vuLhSSPFAw57kYURv4tzXFL6LSnd78bkjqdmE3USedkbpXJUPA1tdzKfuYSL7PianceqAhwL2UkA/<0;1>/*))#cch6wrnp";

// Parse the descriptor and create the watch only wallet
let descriptor: WolletDescriptor = desc.parse()?;
let mut wollet = WolletBuilder::new(
   ElementsNetwork::LiquidTestnet,
   descriptor,
).build()?;

// Generate the address
let addr = wollet.address(None)?;
println!("Address: {} (index {})", addr.address(), addr.index());

Sync wallet

full_scan_with_electrum_client};
// Use an Electrum server
let electrum_url = ElectrumUrl::new("elements-testnet.blockstream.info:50002", true, true)?;
let mut electrum_client = ElectrumClient::new(&electrum_url)?;
full_scan_with_electrum_client(&mut wollet, &mut electrum_client)?;

// Print a summary of the wallet transactions
for tx in wollet.transactions()?.into_iter().rev() {
    println!("TXID: {}, balance {:?}", tx.txid, tx.balance);
}

Create transaction

// Create a transaction
let recipient = UnvalidatedRecipient {
    satoshi: 1000,
    address: "tlq1qqgpjea0jcel4tqeln5kyxlrgqx2eh4vw67ecswm54476mddy3n0klrlmty5gn0wsdw4045rtl2y2wdtr4rdu6v93zds6zn8xd".to_string(),
    asset: "144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49".to_string(),
};
let pset = wollet
    .tx_builder()
    .add_unvalidated_recipient(&recipient)?
    .finish()?;

// Then pass the PSET to the signer(s) for them to sign.

Dependencies

~29–52MB
~721K SLoC