Skip to content

Commit aeb6265

Browse files
committed
docs: [WIP] Initial work on intent tracker example
1 parent 9ec1a6b commit aeb6265

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

wallet/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ bdk_chain = { version = "0.23.1", features = ["rusqlite"] }
4444
bdk_wallet = { path = ".", features = ["rusqlite", "file_store", "test-utils"] }
4545
anyhow = "1"
4646
rand = "^0.8"
47+
bdk_testenv = "0.13"
48+
bdk_bitcoind_rpc = { version = "0.20" }
4749

4850
[package.metadata.docs.rs]
4951
all-features = true
@@ -58,3 +60,7 @@ required-features = ["all-keys"]
5860
name = "miniscriptc"
5961
path = "examples/compiler.rs"
6062
required-features = ["compiler"]
63+
64+
[[example]]
65+
name = "intent_tracker"
66+
path = "examples/intent_tracker.rs"

wallet/examples/intent_tracker.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use std::{str::FromStr, sync::Arc, time::Duration};
2+
3+
use anyhow::Context;
4+
use bdk_testenv::{bitcoincore_rpc::RpcApi, TestEnv};
5+
use bdk_wallet::{KeychainKind, SignOptions, Wallet};
6+
use bitcoin::{Amount, Network, Txid};
7+
8+
const DESCRIPTOR: &str = bdk_testenv::utils::DESCRIPTORS[3];
9+
10+
fn main() -> anyhow::Result<()> {
11+
let env = TestEnv::new().context("failed to start testenv")?;
12+
env.mine_blocks(101, None)
13+
.context("failed to mine blocks")?;
14+
15+
let mut wallet = Wallet::create_single(DESCRIPTOR)
16+
.network(Network::Regtest)
17+
.create_wallet_no_persist()
18+
.context("failed to construct wallet")?;
19+
20+
let mut emitter = bdk_bitcoind_rpc::Emitter::new(
21+
env.rpc_client(),
22+
wallet.latest_checkpoint(),
23+
0,
24+
wallet
25+
.transactions()
26+
.filter(|tx| tx.chain_position.is_unconfirmed())
27+
.map(|tx| tx.tx_node.txid),
28+
);
29+
while let Some(block_event) = emitter.next_block()? {
30+
wallet.apply_block(&block_event.block, block_event.block_height())?;
31+
}
32+
33+
// Receive an unconfirmed tx, spend from it, and the unconfirmed tx get's RBF'ed.
34+
// Our API should be able to recognise that the outgoing tx became evicted and allow the caller
35+
// to respond accordingly.
36+
let wallet_addr = wallet.next_unused_address(KeychainKind::External).address;
37+
let remote_addr = env
38+
.rpc_client()
39+
.get_new_address(None, None)?
40+
.assume_checked();
41+
let incoming_txid = env.send(&wallet_addr, Amount::ONE_BTC)?;
42+
43+
let mempool_event = emitter.mempool()?;
44+
wallet.apply_evicted_txs(mempool_event.evicted_ats());
45+
wallet.apply_unconfirmed_txs(mempool_event.new_txs);
46+
assert_eq!(wallet.balance().total(), Amount::ONE_BTC);
47+
48+
// Create & broadcast outgoing tx.
49+
let mut tx_builder = wallet.build_tx();
50+
tx_builder.add_recipient(remote_addr, Amount::ONE_BTC / 2);
51+
let mut psbt = tx_builder.finish()?;
52+
assert!(wallet.sign(&mut psbt, SignOptions::default())?);
53+
let outgoing_tx = psbt.extract_tx()?;
54+
wallet.track_tx(outgoing_tx.clone());
55+
assert_eq!(wallet.uncanonical_txs().count(), 1);
56+
57+
// Sync.
58+
let outgoing_txid = env.rpc_client().send_raw_transaction(&outgoing_tx)?;
59+
env.wait_until_electrum_sees_txid(outgoing_txid, Duration::from_secs(5))?;
60+
let mempool_event = emitter.mempool()?;
61+
// TODO: Why is `outgoing_txid` not emitted?
62+
println!("mempool_event: {mempool_event:#?}");
63+
wallet.apply_evicted_txs(mempool_event.evicted_ats());
64+
wallet.apply_unconfirmed_txs(mempool_event.new_txs);
65+
let tx = wallet
66+
.canonical_txs()
67+
.find(|tx| tx.tx_node.txid == outgoing_txid)
68+
.expect("must find outgoing tx");
69+
assert_eq!(wallet.uncanonical_txs().count(), 0);
70+
71+
// RBF incoming tx.
72+
let res = env
73+
.rpc_client()
74+
.call::<serde_json::Value>("bumpfee", &[incoming_txid.to_string().into()])?;
75+
let incoming_replacement_txid = Txid::from_str(res.get("txid").unwrap().as_str().unwrap())?;
76+
77+
let mempool_event = emitter.mempool()?;
78+
wallet.apply_evicted_txs(mempool_event.evicted_ats());
79+
wallet.apply_unconfirmed_txs(mempool_event.new_txs);
80+
81+
for uncanonical_tx in wallet.uncanonical_txs() {}
82+
83+
Ok(())
84+
}

0 commit comments

Comments
 (0)