Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
run: yarn lint
- name: Test
working-directory: tests/node
run: yarn build && yarn jest --testPathIgnorePatterns='integration/esplora'
run: yarn build && yarn jest --testPathIgnorePatterns='integration/(esplora|events)'

esplora-integration:
name: Esplora integration tests
Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
run: sleep 10
- name: Run Esplora integration tests
working-directory: tests/node
run: NETWORK=regtest ESPLORA_URL=http://localhost:8094/regtest/api yarn jest --testPathPattern='integration/esplora'
run: NETWORK=regtest ESPLORA_URL=http://localhost:8094/regtest/api yarn jest --runInBand --testPathPattern='integration/(esplora|events)'
- name: Stop Esplora
if: always()
run: docker compose -f tests/docker-compose.yml down
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `WalletEvent` type and `Wallet::apply_update_events` for reacting to wallet state changes ([#19](https://github.com/bitcoindevkit/bdk-wasm/issues/19))
- Upgrade BDK to 2.3.0 with new API wrappers ([#14](https://github.com/bitcoindevkit/bdk-wasm/pull/14)):
- `Wallet::create_from_two_path_descriptor` (BIP-389 multipath descriptors)
- `TxBuilder::exclude_unconfirmed` and `TxBuilder::exclude_below_confirmations`
Expand Down
10 changes: 9 additions & 1 deletion src/bitcoin/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
types::{
AddressInfo, Amount, Balance, ChangeSet, CheckPoint, FeeRate, FullScanRequest, KeychainKind, LocalOutput,
Network, NetworkKind, OutPoint, Psbt, ScriptBuf, SentAndReceived, SpkIndexed, SyncRequest, Transaction, Txid,
Update,
Update, WalletEvent,
},
};

Expand Down Expand Up @@ -97,6 +97,14 @@ impl Wallet {
Ok(())
}

/// Apply an update and return wallet events describing what changed.
///
/// Returns a list of `WalletEvent`s such as new transactions, confirmations, replacements, etc.
pub fn apply_update_events(&self, update: Update) -> JsResult<Vec<WalletEvent>> {
let events = self.0.borrow_mut().apply_update_events(update)?;
Ok(events.into_iter().map(WalletEvent::from).collect())
}

#[wasm_bindgen(getter)]
pub fn network(&self) -> Network {
self.0.borrow().network().into()
Expand Down
121 changes: 121 additions & 0 deletions src/types/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use bdk_wallet::event::WalletEvent as BdkWalletEvent;
use wasm_bindgen::prelude::wasm_bindgen;

use super::{BlockId, ConfirmationBlockTime, Transaction, Txid};

/// The kind of wallet event.
#[wasm_bindgen]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum WalletEventKind {
/// The chain tip changed.
ChainTipChanged = "chain_tip_changed",
/// A transaction was confirmed.
TxConfirmed = "tx_confirmed",
/// A transaction was unconfirmed (reorg).
TxUnconfirmed = "tx_unconfirmed",
/// A transaction was replaced.
TxReplaced = "tx_replaced",
/// A transaction was dropped.
TxDropped = "tx_dropped",
}

/// An event representing a change to the wallet state.
///
/// Returned by `Wallet::apply_update_events`.
#[wasm_bindgen]
pub struct WalletEvent(BdkWalletEvent);

#[wasm_bindgen]
impl WalletEvent {
/// The kind of event.
#[wasm_bindgen(getter)]
pub fn kind(&self) -> WalletEventKind {
match &self.0 {
BdkWalletEvent::ChainTipChanged { .. } => WalletEventKind::ChainTipChanged,
BdkWalletEvent::TxConfirmed { .. } => WalletEventKind::TxConfirmed,
BdkWalletEvent::TxUnconfirmed { .. } => WalletEventKind::TxUnconfirmed,
BdkWalletEvent::TxReplaced { .. } => WalletEventKind::TxReplaced,
BdkWalletEvent::TxDropped { .. } => WalletEventKind::TxDropped,
_ => WalletEventKind::ChainTipChanged, // non_exhaustive fallback
}
}

/// The transaction id, if applicable.
///
/// Available for: `tx_confirmed`, `tx_unconfirmed`, `tx_replaced`, `tx_dropped`.
#[wasm_bindgen(getter)]
pub fn txid(&self) -> Option<Txid> {
match &self.0 {
BdkWalletEvent::TxConfirmed { txid, .. }
| BdkWalletEvent::TxUnconfirmed { txid, .. }
| BdkWalletEvent::TxReplaced { txid, .. }
| BdkWalletEvent::TxDropped { txid, .. } => Some((*txid).into()),
_ => None,
}
}

/// The transaction, if applicable.
///
/// Available for: `tx_confirmed`, `tx_unconfirmed`, `tx_replaced`, `tx_dropped`.
#[wasm_bindgen(getter)]
pub fn tx(&self) -> Option<Transaction> {
match &self.0 {
BdkWalletEvent::TxConfirmed { tx, .. }
| BdkWalletEvent::TxUnconfirmed { tx, .. }
| BdkWalletEvent::TxReplaced { tx, .. }
| BdkWalletEvent::TxDropped { tx, .. } => Some(tx.as_ref().clone().into()),
_ => None,
}
}

/// The old chain tip, for `chain_tip_changed` events.
#[wasm_bindgen(getter)]
pub fn old_tip(&self) -> Option<BlockId> {
match &self.0 {
BdkWalletEvent::ChainTipChanged { old_tip, .. } => Some((*old_tip).into()),
_ => None,
}
}

/// The new chain tip, for `chain_tip_changed` events.
#[wasm_bindgen(getter)]
pub fn new_tip(&self) -> Option<BlockId> {
match &self.0 {
BdkWalletEvent::ChainTipChanged { new_tip, .. } => Some((*new_tip).into()),
_ => None,
}
}

/// The confirmation block time, for `tx_confirmed` events.
#[wasm_bindgen(getter)]
pub fn block_time(&self) -> Option<ConfirmationBlockTime> {
match &self.0 {
BdkWalletEvent::TxConfirmed { block_time, .. } => Some(block_time.into()),
_ => None,
}
}

/// The previous confirmation block time, if the transaction was previously confirmed.
///
/// Available for: `tx_confirmed` (reorg), `tx_unconfirmed` (reorg).
#[wasm_bindgen(getter)]
pub fn old_block_time(&self) -> Option<ConfirmationBlockTime> {
match &self.0 {
BdkWalletEvent::TxConfirmed {
old_block_time: Some(bt),
..
}
| BdkWalletEvent::TxUnconfirmed {
old_block_time: Some(bt),
..
} => Some(ConfirmationBlockTime::from(bt)),
_ => None,
}
}
}

impl From<BdkWalletEvent> for WalletEvent {
fn from(inner: BdkWalletEvent) -> Self {
WalletEvent(inner)
}
}
2 changes: 2 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod chain;
mod changeset;
mod checkpoint;
mod error;
mod event;
mod fee;
mod input;
mod keychain;
Expand All @@ -24,6 +25,7 @@ pub use chain::*;
pub use changeset::*;
pub use checkpoint::*;
pub use error::*;
pub use event::*;
pub use fee::*;
pub use input::*;
pub use keychain::*;
Expand Down
Loading