#wallet #descriptor #liquid #transaction #lwk #ct #wollet

lwk_wollet

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

9 releases (breaking)

new 0.9.0 Feb 27, 2025
0.8.0 Oct 14, 2024
0.7.0 Jul 5, 2024
0.5.1 May 22, 2024
0.1.0 Jan 26, 2024

#86 in Magic Beans

Download history 12/week @ 2024-11-04 2/week @ 2024-11-11 34/week @ 2024-11-18 8/week @ 2024-11-25 2/week @ 2024-12-02 28/week @ 2024-12-09 25/week @ 2024-12-16 14/week @ 2025-01-20 18/week @ 2025-01-27 20/week @ 2025-02-03 75/week @ 2025-02-10 25/week @ 2025-02-17

144 downloads per month
Used in 4 crates (3 directly)

MIT OR BSD-2-Clause

275KB
6K 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 = Wollet::new(
    ElementsNetwork::LiquidTestnet,
    NoPersist::new(), // Do not persist data
    descriptor,
)?;

// 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

~27–44MB
~594K SLoC