Skip to main content

sidestr_wallet/
error.rs

1//! The one error type every fallible function in this crate returns.
2//!
3//! siding's `spend.mjs` throws `Error` objects whose *messages* are the
4//! contract its callers and tests read (`insufficient: … sats mature, …
5//! needed`, `a peg-out burns at least … sats`, `bad address …`). The
6//! variants here keep that wording, so a message from this crate reads like
7//! one from the reference, while a caller can match on the variant.
8
9/// Everything that can go wrong between "I want to pay" and a transaction
10/// the producer accepts.
11#[derive(Debug, thiserror::Error)]
12#[non_exhaustive]
13pub enum Error {
14    /// The amount is zero (`spend.mjs`: "the amount is a whole number of sats").
15    #[error("the amount is a whole number of sats")]
16    BadAmount,
17    /// The destination is neither a script hex nor a segwit address under
18    /// any prefix (`spend.mjs resolveTo`: "bad address …").
19    #[error("bad address {0}")]
20    BadDestination(String),
21    /// The mature coins do not cover the amount plus the fee bound
22    /// (`spend.mjs`: "insufficient: … sats mature, … needed").
23    #[error("insufficient: {have} sats mature, {need} needed")]
24    Insufficient {
25        /// Sats the picked coins sum to.
26        have: u64,
27        /// Amount plus the fee bound.
28        need: u64,
29    },
30    /// The coins covered the bound but not the fee the size came to
31    /// (`spend.mjs`: "insufficient coins for … plus the …-sat minimum fee").
32    #[error("insufficient coins for {amount} plus the {fee}-sat minimum fee")]
33    InsufficientForFee {
34        /// The amount wanted.
35        amount: u64,
36        /// The fee the sized transaction needs.
37        fee: u64,
38    },
39    /// A burn below the document's `pegoutMin` (SPEC 7; `spend.mjs`: "a
40    /// peg-out burns at least … sats").
41    #[error("a peg-out burns at least {min} sats, not {value}")]
42    BelowPegoutMin {
43        /// The value asked for.
44        value: u64,
45        /// The document's `pegoutMin`.
46        min: u64,
47    },
48    /// An explicit fee under the producer's `minFeeRate` policy, in the
49    /// words `State::submit` would refuse it with.
50    #[error("fee {fee} is below the minimum {min} sats ({vsize} vB at {rate} sat/vB)")]
51    FeeBelowMinimum {
52        /// The fee given.
53        fee: u64,
54        /// The least the producer accepts for this size.
55        min: u64,
56        /// The transaction's virtual size.
57        vsize: u64,
58        /// The document's `minFeeRate`.
59        rate: u64,
60    },
61    /// An output below Bitcoin's dust threshold for its script: the chain
62    /// would accept it and no wallet could economically spend it. The
63    /// reference does not check; this crate does (see the crate docs).
64    #[error("{value} sats to {script} is dust: at least {min} sats")]
65    Dust {
66        /// The value asked for.
67        value: u64,
68        /// The dust threshold for that script.
69        min: u64,
70        /// The script, hex.
71        script: String,
72    },
73    /// A parent address for the wrong network: a peg-in to a `bc1…`
74    /// address beside `tbtc4`, or the reverse (SPEC 6, 3.2).
75    #[error("{address} is not a {network} address: the parent is {parent}")]
76    WrongNetwork {
77        /// The address given.
78        address: String,
79        /// The network the parent alias resolves to.
80        network: String,
81        /// The parent alias from the document.
82        parent: String,
83    },
84    /// A parent-side marker (peg-in, peg-out record) longer than the
85    /// parent's 80-byte `OP_RETURN` relay policy allows, or any marker push
86    /// over the 255 bytes the shared grammar reads back (a 61-byte peg-in
87    /// marker for a 15-byte chain id fits).
88    #[error(
89        "marker of {0} bytes exceeds the parent's 80-byte data limit; the chain id is too long"
90    )]
91    MarkerTooLong(usize),
92    /// The [`SpendPolicy`](crate::policy::SpendPolicy) refused the intent.
93    #[error("policy refused: {0}")]
94    Policy(String),
95    /// The [`SpendSigner`](crate::key::SpendSigner) could not sign.
96    #[error("signer: {0}")]
97    Signer(String),
98    /// An issued-asset build the `assets` view would not read as asked
99    /// (SPEC 12): too little of the asset, a memo shaped like an assets
100    /// record, an input carrying another asset.
101    #[error("asset: {0}")]
102    Asset(String),
103    /// A producer answered `{"error": …}` to a `POST /tx`.
104    #[error("producer refused: {0}")]
105    Refused(String),
106    /// JSON that does not parse or does not fit the shape.
107    #[error("json: {0}")]
108    Json(#[from] serde_json::Error),
109    /// Hex or bytes that do not decode.
110    #[error("encoding: {0}")]
111    Encoding(String),
112    /// An error from `sidestr-core`: a document naming an unknown parent, a
113    /// marker that cannot be built.
114    #[error(transparent)]
115    Core(#[from] sidestr_core::Error),
116    /// A secp256k1 failure: a derived scalar out of range, a bad key.
117    #[error("secp256k1: {0}")]
118    Secp(#[from] bitcoin::secp256k1::Error),
119    /// An HTTP failure talking to a producer (feature `client`).
120    #[cfg(feature = "client")]
121    #[error("http: {0}")]
122    Http(String),
123}
124
125/// `Result` with this crate's [`Error`].
126pub type Result<T> = core::result::Result<T, Error>;