1use bitcoin::relative;
2use bitcoin::Amount;
3use bitcoin::OutPoint;
4use bitcoin::ScriptBuf;
5use bitcoin::TxOut;
6use std::time::Duration;
7
8pub mod arknote;
9pub mod asset;
10pub mod batch;
11pub mod boarding_output;
12pub mod coin_select;
13pub mod conversions;
14pub mod extension;
15pub mod history;
16pub mod intent;
17pub mod introspector;
18pub mod script;
19pub mod send;
20pub mod server;
21pub mod unilateral_exit;
22pub mod vhtlc;
23pub mod vtxo;
24
25mod ark_address;
26mod error;
27mod tree_tx_output_script;
28mod tx_graph;
29mod vtxo_list;
30
31pub use ark_address::ArkAddress;
32pub use arknote::ArkNote;
33pub use boarding_output::BoardingOutput;
34pub use error::Error;
35pub use error::ErrorContext;
36pub use script::extract_sequence_from_csv_sig_script;
37pub use server::Asset;
38pub use server::AssetInfo;
39pub use tx_graph::TxGraph;
40pub use tx_graph::TxGraphChunk;
41pub use unilateral_exit::build_anchor_tx;
42pub use unilateral_exit::build_unilateral_exit_tree_txids;
43pub use unilateral_exit::SelectedUtxo;
44pub use unilateral_exit::UtxoCoinSelection;
45pub use vtxo::Vtxo;
46pub use vtxo_list::VtxoList;
47
48pub const UNSPENDABLE_KEY: &str =
49 "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
50
51pub const VTXO_INPUT_INDEX: usize = 0;
52
53pub const VTXO_TAPROOT_KEY: [u8; 7] = [116, 97, 112, 116, 114, 101, 101];
55
56pub const VTXO_CONDITION_KEY: [u8; 9] = [99, 111, 110, 100, 105, 116, 105, 111, 110];
58
59pub const VTXO_TREE_EXPIRY_PSBT_KEY: [u8; 6] = [101, 120, 112, 105, 114, 121];
61
62pub const VTXO_COSIGNER_PSBT_KEY: [u8; 8] = [99, 111, 115, 105, 103, 110, 101, 114];
68
69pub const DEFAULT_DERIVATION_PATH: &str = "m/83696968'/11811'/0";
70
71pub const MAINNET_LEGACY_UNILATERAL_EXIT_DELAY_SECS: u32 = 605_184;
76
77pub fn candidate_exit_delays(
82 current: bitcoin::Sequence,
83 network: bitcoin::Network,
84) -> Result<Vec<bitcoin::Sequence>, Error> {
85 let mut delays = vec![current];
86
87 if network == bitcoin::Network::Bitcoin {
88 let legacy =
89 bitcoin::Sequence::from_seconds_ceil(MAINNET_LEGACY_UNILATERAL_EXIT_DELAY_SECS)
90 .map_err(Error::ad_hoc)?;
91 if !delays.contains(&legacy) {
92 delays.push(legacy);
93 }
94 }
95
96 Ok(delays)
97}
98
99const ANCHOR_SCRIPT_PUBKEY: [u8; 4] = [0x51, 0x02, 0x4e, 0x73];
100
101#[derive(Clone, Copy, Debug)]
103pub struct ExplorerUtxo {
104 pub outpoint: OutPoint,
105 pub amount: Amount,
106 pub confirmation_blocktime: Option<u64>,
107 pub confirmations: u64,
108 pub is_spent: bool,
109}
110
111pub fn anchor_output() -> TxOut {
112 let script_pubkey = ScriptBuf::from_bytes(ANCHOR_SCRIPT_PUBKEY.to_vec());
113
114 TxOut {
115 value: Amount::ZERO,
116 script_pubkey,
117 }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
121pub(crate) enum ExitDelayKind {
122 Time(Duration),
123 Blocks(u64),
124}
125
126impl ExitDelayKind {
127 pub(crate) fn from_sequence(sequence: bitcoin::Sequence) -> Result<Self, Error> {
128 let kind = match sequence
129 .to_relative_lock_time()
130 .ok_or_else(|| Error::ad_hoc("exit delay is not a relative locktime"))?
131 {
132 relative::LockTime::Time(time) => {
133 Self::Time(Duration::from_secs(time.value() as u64 * 512))
134 }
135 relative::LockTime::Blocks(height) => Self::Blocks(height.value() as u64),
136 };
137
138 Ok(kind)
139 }
140}