Skip to content

Full Wallet Example

This page illustrates core wallet functionality, including:

  • Generating descriptors
  • Recovering a wallet with descriptors
  • Creating and broadcasting a transaction

Tip

The logic for this page is broken down in in 3 separate examples in the examples source code. If you are following along with the code examples you will need to copy and paste descriptors between them.

Generating Descriptors

First we create signet descriptors for our wallet.

examples/rust/descriptors/src/main.rs
let mut seed: [u8; 32] = [0u8; 32];
rand::thread_rng().fill_bytes(&mut seed);

let network: Network = Network::Signet;
let xprv: Xpriv = Xpriv::new_master(network, &seed).unwrap();
println!("Generated Master Private Key:\n{}\nWarning: be very careful with private keys when using MainNet! We are logging these values for convenience only because this is an example on SigNet.\n", xprv);

let (descriptor, key_map, _) = Bip86(xprv, KeychainKind::External)
    .build(Network::Signet)
    .expect("Failed to build external descriptor");

let (change_descriptor, change_key_map, _) = Bip86(xprv, KeychainKind::Internal)
    .build(Network::Signet)
    .expect("Failed to build internal descriptor");

let descriptor_string_priv = descriptor.to_string_with_secret(&key_map);
let change_descriptor_string_priv = descriptor.to_string_with_secret(&change_key_map);

Notice we are creating private descriptors here in order to sign transactions later on.

Recovering a Wallet with Descriptors

Next, lets use those descriptors to load up our wallet. Replace the descriptors in the quickstart example with either your private or publickey descriptors (either will work here) and run it to sync a wallet, check the balance, and generate a new address:

examples/rust/quickstart/src/main.rs
1
2
3
// Reveal a new address from your external keychain
let address: AddressInfo = wallet.reveal_next_address(KeychainKind::External);
println!("Generated address {} at index {}", address.address, address.index);

Request satoshis from the Mutinynet faucet

We can now use our new address to request some sats from the Mutinynet faucet. After requesting sats, you can view the transaction in their Mempool Explorer instance (click the link on the faucet confirmation page or put the txid in the search bar of the mempool explorer). After a minute or so you should see the transaction confirmed. We can also re-run the quickstart example and see that our wallet now has some funds!

Creating and Broadcasting a Transaction

Finally we use the wallet to send some satoshis. Put your private descriptors into the transaction example and run it to create, sign, and broadcast a transaction.

examples/rust/transaction/src/main.rs
const DESCRIPTOR_PRIVATE_EXTERNAL: &str = "[your private external descriptor here ...]";
const DESCRIPTOR_PRIVATE_INTERNAL: &str = "[your private internal descriptor here ...]";

fn main() -> Result<(), anyhow::Error> {
    let (mut wallet, client) = recover_wallet();

    // Use the Mutinynet faucet return address
    let address = Address::from_str("tb1qd28npep0s8frcm3y7dxqajkcy2m40eysplyr9v")
        .unwrap()
        .require_network(Network::Signet)
        .unwrap();

    // Transaction Logic
    let mut tx_builder = wallet.build_tx();
    tx_builder.add_recipient(address.script_pubkey(), SEND_AMOUNT);

    let mut psbt = tx_builder.finish()?;
    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
    assert!(finalized);

    let tx = psbt.extract_tx()?;
    client.broadcast(&tx)?;
    println!("Tx broadcasted! Txid: {}", tx.compute_txid());

    Ok(())
}

Again we can view the transaction in the Mutinynet explorer or re-run the quickstart example to see that our wallet has less funds.