1
2#[macro_use] extern crate lazy_static;
3#[macro_use] extern crate serde as serde_crate;
4
5pub extern crate bitcoin;
6
7pub mod cpfp;
8pub mod fee;
9
10#[cfg(feature = "bdk")]
11pub mod bdk;
12#[cfg(feature = "esplora")]
13pub mod esplora;
14#[cfg(feature = "rpc")]
15pub mod rpc;
16pub mod serde;
17
18pub use mbitcoin::{
19 AmountExt, FeeRateExt, TaprootSpendInfoExt, KeypairExt, TransactionExt, TxOutExt,
20};
21
22#[path = "bitcoin.rs"]
23mod mbitcoin;
24
25use std::{fmt, str::FromStr};
26
27use bitcoin::{Amount, BlockHash};
28
29pub const DEEPLY_CONFIRMED: BlockHeight = 100;
32
33pub const P2TR_DUST_VB: u64 = 110;
34pub const P2TR_DUST_SAT: u64 = P2TR_DUST_VB * 3;
36pub const P2TR_DUST: Amount = Amount::from_sat(P2TR_DUST_SAT);
37
38pub const P2WPKH_DUST_VB: u64 = 90;
39pub const P2WPKH_DUST_SAT: u64 = P2WPKH_DUST_VB * 3;
41pub const P2WPKH_DUST: Amount = Amount::from_sat(P2WPKH_DUST_SAT);
42
43pub const P2PKH_DUST_VB: u64 = 182;
44pub const P2PKH_DUST_SAT: u64 = P2PKH_DUST_VB * 3;
46pub const P2PKH_DUST: Amount = Amount::from_sat(P2PKH_DUST_SAT);
47
48pub const P2SH_DUST_VB: u64 = 180;
49pub const P2SH_DUST_SAT: u64 = P2SH_DUST_VB * 3;
51pub const P2SH_DUST: Amount = Amount::from_sat(P2SH_DUST_SAT);
52
53pub const P2WSH_DUST_VB: u64 = 110;
54pub const P2WSH_DUST_SAT: u64 = P2WSH_DUST_VB * 3;
56pub const P2WSH_DUST: Amount = Amount::from_sat(P2WSH_DUST_SAT);
57
58pub const TAPROOT_KEYSPEND_WEIGHT: usize = 66;
60
61pub type BlockHeight = u32;
63pub type BlockDelta = u16;
65#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
69pub struct BlockRef {
70 pub height: BlockHeight,
71 pub hash: BlockHash,
72}
73
74impl fmt::Display for BlockRef {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 write!(f, "{}:{}", self.height, self.hash)
77 }
78}
79
80impl fmt::Debug for BlockRef {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 fmt::Display::fmt(self, f)
83 }
84}
85
86impl FromStr for BlockRef {
87 type Err = &'static str;
88
89 fn from_str(s: &str) -> Result<Self, Self::Err> {
90 let mut parts = s.splitn(2, ':');
91 Ok(BlockRef {
92 height: parts.next().expect("always one part")
93 .parse().map_err(|_| "invalid height")?,
94 hash: parts.next().ok_or("should be <height>:<hash> string")?
95 .parse().map_err(|_| "invalid hash")?,
96 })
97 }
98}
99
100impl serde_crate::Serialize for BlockRef {
101 fn serialize<S: serde_crate::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
102 s.collect_str(self)
103 }
104}
105
106impl<'de> serde_crate::Deserialize<'de> for BlockRef {
107 fn deserialize<D: serde_crate::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
108 struct Visitor;
109 impl<'de> serde_crate::de::Visitor<'de> for Visitor {
110 type Value = BlockRef;
111 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, "a BlockRef")
113 }
114 fn visit_str<E: serde_crate::de::Error>(self, v: &str) -> Result<Self::Value, E> {
115 BlockRef::from_str(v).map_err(serde_crate::de::Error::custom)
116 }
117 }
118 d.deserialize_str(Visitor)
119 }
120}
121
122#[cfg(feature = "bdk")]
123impl From<bdk_wallet::chain::BlockId> for BlockRef {
124 fn from(id: bdk_wallet::chain::BlockId) -> Self {
125 Self {
126 height: id.height,
127 hash: id.hash,
128 }
129 }
130}
131
132#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
133pub enum TxStatus {
134 Confirmed(BlockRef),
135 Mempool,
136 NotFound,
137}
138
139impl TxStatus {
140 pub fn confirmed_height(&self) -> Option<BlockHeight> {
141 match self {
142 TxStatus::Confirmed(block_ref) => Some(block_ref.height),
143 _ => None,
144 }
145 }
146
147 pub fn confirmed_in(&self) -> Option<BlockRef> {
148 match self {
149 TxStatus::Confirmed(block_ref) => Some(*block_ref),
150 _ => None,
151 }
152 }
153}
154