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