fn test_get_funded_wallet_sent_and_received() {
let (wallet, txid) = get_funded_wallet(get_test_wpkh());
- let mut tx_amounts: Vec<(Txid, (u64, u64))> = wallet
+ let mut tx_amounts: Vec<(Txid, (Amount, Amount))> = wallet
.transactions()
.map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node)))
.collect();
// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
// sats are the transaction fee.
- assert_eq!(sent, 76_000);
- assert_eq!(received, 50_000);
+ assert_eq!(sent.to_sat(), 76_000);
+ assert_eq!(received.to_sat(), 50_000);
}
#[test]
"should add an additional input since 25_000 < 30_000"
);
assert_eq!(
- sent_received.0, 75_000,
+ sent_received.0,
+ Amount::from_sat(75_000),
"total should be sum of both inputs"
);
}
wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
assert_eq!(
- sent_received.0 - sent_received.1,
+ (sent_received.0 - sent_received.1).to_sat(),
10_000 + fee.unwrap_or(0),
"we should have only net spent ~10_000"
);
assert_eq!(sent_received.0, original_sent_received.0);
assert_eq!(
- sent_received.1 + fee.unwrap_or(0),
- original_sent_received.1 + original_fee.unwrap_or(0)
+ sent_received.1 + Amount::from_sat(fee.unwrap_or(0)),
+ original_sent_received.1 + Amount::from_sat(original_fee.unwrap_or(0))
);
assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0));
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
+ .value,
sent_received.1
);
assert_eq!(sent_received.0, original_sent_received.0);
assert_eq!(
- sent_received.1 + fee.unwrap_or(0),
- original_sent_received.1 + original_fee.unwrap_or(0)
+ sent_received.1 + Amount::from_sat(fee.unwrap_or(0)),
+ original_sent_received.1 + Amount::from_sat(original_fee.unwrap_or(0))
);
assert!(
fee.unwrap_or(0) > original_fee.unwrap_or(0),
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
+ .value,
sent_received.1
);
let tx = &psbt.unsigned_tx;
assert_eq!(tx.output.len(), 1);
assert_eq!(
- tx.output[0].value.to_sat() + fee.unwrap_or(0),
+ tx.output[0].value + Amount::from_sat(fee.unwrap_or(0)),
sent_received.0
);
assert_eq!(tx.output.len(), 1);
assert_eq!(
- tx.output[0].value.to_sat() + fee.unwrap_or(0),
+ tx.output[0].value + Amount::from_sat(fee.unwrap_or(0)),
sent_received.0
);
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
- assert_eq!(original_sent_received.0, 25_000);
+ assert_eq!(original_sent_received.0, Amount::from_sat(25_000));
// for the new feerate, it should be enough to reduce the output, but since we specify
// `drain_wallet` we expect to spend everything
let psbt = builder.finish().unwrap();
let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx"));
- assert_eq!(sent_received.0, 75_000);
+ assert_eq!(sent_received.0, Amount::from_sat(75_000));
}
#[test]
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap();
- assert_eq!(original_sent_received.0, 25_000);
+ assert_eq!(original_sent_received.0, Amount::from_sat(25_000));
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder
let sent_received =
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
- assert_eq!(sent_received.0, original_details.0 + 25_000);
- assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
+ assert_eq!(
+ sent_received.0,
+ original_details.0 + Amount::from_sat(25_000)
+ );
+ assert_eq!(
+ Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
+ Amount::from_sat(30_000)
+ );
let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
+ .value,
sent_received.1
);
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
- assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
- assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
+ assert_eq!(
+ sent_received.0,
+ original_sent_received.0 + Amount::from_sat(25_000)
+ );
+ assert_eq!(
+ Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
+ Amount::from_sat(30_000)
+ );
let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
+ .value,
sent_received.1
);
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
- let original_send_all_amount = original_sent_received.0 - original_fee.unwrap_or(0);
- assert_eq!(sent_received.0, original_sent_received.0 + 50_000);
+ let original_send_all_amount =
+ original_sent_received.0 - Amount::from_sat(original_fee.unwrap_or(0));
+ assert_eq!(
+ sent_received.0,
+ original_sent_received.0 + Amount::from_sat(50_000)
+ );
assert_eq!(
sent_received.1,
- 75_000 - original_send_all_amount - fee.unwrap_or(0)
+ Amount::from_sat(75_000) - original_send_all_amount - Amount::from_sat(fee.unwrap_or(0))
);
let tx = &psbt.unsigned_tx;
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- Amount::from_sat(original_send_all_amount)
+ original_send_all_amount
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
- 75_000 - original_send_all_amount - fee.unwrap_or(0)
+ .value,
+ Amount::from_sat(75_000) - original_send_all_amount - Amount::from_sat(fee.unwrap_or(0))
);
assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb_unchecked(50), @add_signature);
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
- assert_eq!(original_sent_received.1, 5_000 - original_fee.unwrap_or(0));
+ assert_eq!(
+ original_sent_received.1,
+ Amount::from_sat(5_000 - original_fee.unwrap_or(0))
+ );
- assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
+ assert_eq!(
+ sent_received.0,
+ original_sent_received.0 + Amount::from_sat(25_000)
+ );
assert_eq!(fee.unwrap_or(0), 30_000);
- assert_eq!(sent_received.1, 0);
+ assert_eq!(sent_received.1, Amount::ZERO);
let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
- assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
- assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
+ assert_eq!(
+ sent_received.0,
+ original_sent_received.0 + Amount::from_sat(25_000)
+ );
+ assert_eq!(
+ Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
+ Amount::from_sat(30_000)
+ );
let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
+ .value,
sent_received.1
);
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
- assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
- assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
+ assert_eq!(
+ sent_received.0,
+ original_sent_received.0 + Amount::from_sat(25_000)
+ );
+ assert_eq!(
+ Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
+ Amount::from_sat(30_000)
+ );
let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2);
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value
- .to_sat(),
+ .value,
sent_received.1
);
assert_eq!(
sent_received.0 - sent_received.1,
- 10_000 + fee.unwrap_or(0),
+ Amount::from_sat(10_000 + fee.unwrap_or(0)),
"we should have only net spent ~10_000"
);
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
indexed_tx_graph::Indexer,
};
-use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid};
+use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
/// An index storing [`TxOut`]s that have a script pubkey that matches those in a list.
///
self.spk_indices.get(script)
}
- // TODO: (@leonardo) Should this also be updated to return `(bitcoin::Amount, bitcoin::Amount)` instead of (u64, u64)
/// Computes the total value transfer effect `tx` has on the script pubkeys in `range`. Value is
/// *sent* when a script pubkey in the `range` is on an input and *received* when it is on an
/// output. For `sent` to be computed correctly, the output being spent must have already been
/// scanned by the index. Calculating received just uses the [`Transaction`] outputs directly,
/// so it will be correct even if it has not been scanned.
- pub fn sent_and_received(&self, tx: &Transaction, range: impl RangeBounds<I>) -> (u64, u64) {
- let mut sent = 0;
- let mut received = 0;
+ pub fn sent_and_received(
+ &self,
+ tx: &Transaction,
+ range: impl RangeBounds<I>,
+ ) -> (Amount, Amount) {
+ let mut sent = Amount::ZERO;
+ let mut received = Amount::ZERO;
for txin in &tx.input {
if let Some((index, txout)) = self.txout(txin.previous_output) {
if range.contains(index) {
- sent += txout.value.to_sat();
+ sent += txout.value;
}
}
}
for txout in &tx.output {
if let Some(index) = self.index_of_spk(&txout.script_pubkey) {
if range.contains(index) {
- received += txout.value.to_sat();
+ received += txout.value;
}
}
}
/// for calling [`sent_and_received`] and subtracting sent from received.
///
/// [`sent_and_received`]: Self::sent_and_received
- pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<I>) -> i64 {
+ pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<I>) -> SignedAmount {
let (sent, received) = self.sent_and_received(tx, range);
- received as i64 - sent as i64
+ received.to_signed().expect("valid `SignedAmount`")
+ - sent.to_signed().expect("valid `SignedAmount`")
}
/// Whether any of the inputs of this transaction spend a txout tracked or whether any output
use bdk_chain::{indexed_tx_graph::Indexer, SpkTxOutIndex};
-use bitcoin::{absolute, transaction, Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
+use bitcoin::{
+ absolute, transaction, Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxIn, TxOut,
+};
#[test]
fn spk_txout_sent_and_received() {
}],
};
- assert_eq!(index.sent_and_received(&tx1, ..), (0, 42_000));
- assert_eq!(index.sent_and_received(&tx1, ..1), (0, 42_000));
- assert_eq!(index.sent_and_received(&tx1, 1..), (0, 0));
- assert_eq!(index.net_value(&tx1, ..), 42_000);
+ assert_eq!(
+ index.sent_and_received(&tx1, ..),
+ (Amount::from_sat(0), Amount::from_sat(42_000))
+ );
+ assert_eq!(
+ index.sent_and_received(&tx1, ..1),
+ (Amount::from_sat(0), Amount::from_sat(42_000))
+ );
+ assert_eq!(
+ index.sent_and_received(&tx1, 1..),
+ (Amount::from_sat(0), Amount::from_sat(0))
+ );
+ assert_eq!(index.net_value(&tx1, ..), SignedAmount::from_sat(42_000));
index.index_tx(&tx1);
assert_eq!(
index.sent_and_received(&tx1, ..),
- (0, 42_000),
+ (Amount::from_sat(0), Amount::from_sat(42_000)),
"shouldn't change after scanning"
);
],
};
- assert_eq!(index.sent_and_received(&tx2, ..), (42_000, 50_000));
- assert_eq!(index.sent_and_received(&tx2, ..1), (42_000, 30_000));
- assert_eq!(index.sent_and_received(&tx2, 1..), (0, 20_000));
- assert_eq!(index.net_value(&tx2, ..), 8_000);
+ assert_eq!(
+ index.sent_and_received(&tx2, ..),
+ (Amount::from_sat(42_000), Amount::from_sat(50_000))
+ );
+ assert_eq!(
+ index.sent_and_received(&tx2, ..1),
+ (Amount::from_sat(42_000), Amount::from_sat(30_000))
+ );
+ assert_eq!(
+ index.sent_and_received(&tx2, 1..),
+ (Amount::from_sat(0), Amount::from_sat(20_000))
+ );
+ assert_eq!(index.net_value(&tx2, ..), SignedAmount::from_sat(8_000));
}
#[test]