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