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 = "rpc")]
13pub mod rpc;
14pub mod serde;
15
16pub use mbitcoin::{
17 AmountExt, FeeRateExt, TaprootSpendInfoExt, KeypairExt, TransactionExt, TxOutExt,
18};
19
20#[path = "bitcoin.rs"]
21mod mbitcoin;
22
23use std::{fmt, str::FromStr};
24
25use bitcoin::{Amount, BlockHash};
26
27use serde_crate::ser::SerializeStruct;
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 let mut state = s.serialize_struct("BlockRef", 2)?;
103 state.serialize_field("height", &self.height)?;
104 state.serialize_field("hash", &self.hash)?;
105 state.end()
106 }
107}
108
109impl<'de> serde_crate::Deserialize<'de> for BlockRef {
110 fn deserialize<D: serde_crate::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
111 struct Visitor;
112 impl<'de> serde_crate::de::Visitor<'de> for Visitor {
113 type Value = BlockRef;
114 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(f, "a BlockRef (struct/string)")
116 }
117 fn visit_str<E: serde_crate::de::Error>(self, v: &str) -> Result<Self::Value, E> {
118 BlockRef::from_str(v).map_err(serde_crate::de::Error::custom)
119 }
120 fn visit_map<A: serde_crate::de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
121 let mut height = None;
122 let mut hash = None;
123 while let Some(key) = map.next_key::<&str>()? {
124 match key {
125 "height" => height = Some(map.next_value()?),
126 "hash" => hash = Some(map.next_value()?),
127 _ => {
128 let _ = map.next_value::<serde_crate::de::IgnoredAny>()?;
129 }
130 }
131 }
132 Ok(BlockRef {
133 height: height.ok_or_else(|| serde_crate::de::Error::missing_field("height"))?,
134 hash: hash.ok_or_else(|| serde_crate::de::Error::missing_field("hash"))?,
135 })
136 }
137 }
138 d.deserialize_any(Visitor)
139 }
140}
141
142#[cfg(feature = "bdk")]
143impl From<bdk_wallet::chain::BlockId> for BlockRef {
144 fn from(id: bdk_wallet::chain::BlockId) -> Self {
145 Self {
146 height: id.height,
147 hash: id.hash,
148 }
149 }
150}
151
152#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
153pub enum TxStatus {
154 Confirmed(BlockRef),
155 Mempool,
156 NotFound,
157}
158
159impl TxStatus {
160 pub fn is_confirmed(&self) -> bool {
161 match self {
162 TxStatus::Confirmed(_) => true,
163 _ => false,
164 }
165 }
166
167 pub fn confirmed_height(&self) -> Option<BlockHeight> {
168 match self {
169 TxStatus::Confirmed(block_ref) => Some(block_ref.height),
170 _ => None,
171 }
172 }
173
174 pub fn confirmed_in(&self) -> Option<BlockRef> {
175 match self {
176 TxStatus::Confirmed(block_ref) => Some(*block_ref),
177 _ => None,
178 }
179 }
180}
181