Skip to main content

ark_core/
lib.rs

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
53/// The byte value corresponds to the string "taptree".
54pub const VTXO_TAPROOT_KEY: [u8; 7] = [116, 97, 112, 116, 114, 101, 101];
55
56/// The byte value corresponds to the string "condition".
57pub const VTXO_CONDITION_KEY: [u8; 9] = [99, 111, 110, 100, 105, 116, 105, 111, 110];
58
59/// The byte value corresponds to the string "expiry".
60pub const VTXO_TREE_EXPIRY_PSBT_KEY: [u8; 6] = [101, 120, 112, 105, 114, 121];
61
62/// The cosigner PKs that sign a VTXO TX input are included in the `unknown` key-value map field of
63/// that input in the VTXO PSBT. Since the `unknown` field can be used for any purpose, we know that
64/// a value is a cosigner PK if the corresponding key starts with this prefix.
65///
66/// The byte value corresponds to the string "cosigner".
67pub 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
71/// Mainnet's original unilateral-exit delay (~7 days, in seconds).
72///
73/// arkd currently advertises only the active exit delay in `/info`. Clients that need to discover
74/// historical scripts can probe this legacy mainnet delay alongside the advertised one.
75pub const MAINNET_LEGACY_UNILATERAL_EXIT_DELAY_SECS: u32 = 605_184;
76
77/// Candidate exit-delay set for discovery/watch.
78///
79/// Returns `current` plus, on mainnet only, the hardcoded legacy delay used by older outputs. The
80/// result is deduplicated, so if `current` already equals the legacy value it appears only once.
81pub 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/// Information a UTXO that may be extracted from an on-chain explorer.
102#[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}