Skip to main content

webledgers_teller/
error.rs

1//! The one error type every fallible function in this crate returns.
2//!
3//! The teller throws with a sentence a person reads (`'a withdrawal is at
4//! least 546 sat'`) and its tests match on those words. Every refusal here is
5//! a named variant whose `Display` is the teller's sentence, word for word,
6//! so a page can show it and a test can match either the variant or the
7//! text. The variants this port adds (the ledger event, which the teller's
8//! page reads, and the boundaries Rust types make explicit) say so.
9
10/// Everything the teller refuses, in its own words.
11#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
12pub enum Error {
13    /// `accountOf`: not `did:nostr:<x>`, a bare x or a did:nostr Multikey.
14    #[error("an account is a did:nostr identifier (did:nostr:<64 hex>)")]
15    Account,
16    /// `sats`: not a whole number of satoshis between 0 and 21 million coins.
17    #[error("an amount is a whole number of satoshis")]
18    Amount,
19    /// `newLedger`: the name is empty or longer than 80 characters.
20    #[error("a ledger has a name of up to 80 characters")]
21    Name,
22    /// `checkLedger`: not a `WebLedger`, or no genesis.
23    #[error("not a Web Ledger with a genesis")]
24    NotALedger,
25    /// `checkLedger`: the stored hash is not the hash of the genesis.
26    #[error("the ledger's hash is not the hash of its genesis")]
27    HashMismatch,
28    /// `credit`: the outpoint is not `<64 lowercase hex>:<vout>`.
29    #[error("a deposit is an outpoint txid:vout")]
30    Outpoint,
31    /// `transfer`: an amount of zero.
32    #[error("a transfer moves at least one satoshi")]
33    ZeroTransfer,
34    /// `transfer`, `debit`: the account holds less than the amount.
35    #[error("{account}… has {has} sat, not {wanted}")]
36    Insufficient {
37        /// The first 20 characters of the account's did (`did:nostr:` and
38        /// ten hex digits), as the teller writes it.
39        account: String,
40        /// The balance the account holds.
41        has: u64,
42        /// The amount asked for.
43        wanted: u64,
44    },
45    /// `debit`: below [`crate::MIN_PAY`].
46    #[error("a withdrawal is at least 546 sat")]
47    WithdrawalTooSmall,
48    /// `depositAddress`: the ledger hash is not 64 lowercase hex.
49    #[error("ledgerHash is the ledger's 32-byte hash")]
50    DepositLedgerHash,
51    /// `requestTags`: the ledger hash is not 64 lowercase hex.
52    #[error("ledgerHash is the ledger's hash")]
53    RequestLedgerHash,
54    /// `requestTags`: an op other than join, withdraw or transfer.
55    #[error("op is join, withdraw or transfer")]
56    Op,
57    /// `requestTags`, `parseRequest`: a withdrawal or transfer with no `to`.
58    #[error("a withdrawal or transfer names where to")]
59    NoDestination,
60    /// `parseRequest`: not kind 3700.
61    #[error("not a request (kind 3700)")]
62    NotARequest,
63    /// `parseRequest`: the id or the signature does not verify.
64    #[error("the request does not verify")]
65    Unverified,
66    /// `parseRequest`: the `ledger` tag names another ledger.
67    #[error("a request for another ledger")]
68    OtherLedger,
69    /// `parseRequest`: no valid op, or no id of 8 to 64 lowercase hex.
70    #[error("a request has an op and an id")]
71    OpAndId,
72    /// `planPayout`: below [`crate::MIN_PAY`].
73    #[error("a payout is at least 546 sat")]
74    PayoutTooSmall,
75    /// `planPayout`: a fee rate outside 1 to 1000 sat/vB.
76    #[error("rate 1 to 1000 sat/vB")]
77    Rate,
78    /// `planPayout`: every coin together cannot pay the amount and the fee.
79    #[error("the deposits held ({held} sat) do not cover {amount} sat and the fee")]
80    NotCovered {
81        /// The sum of every coin offered.
82        held: u64,
83        /// The amount to pay.
84        amount: u64,
85    },
86    /// `signPayout`: an input failed the chain's script check.
87    #[error("input {input} did not pass the script check ({reason}); nothing was paid")]
88    ScriptCheck {
89        /// The input's index.
90        input: usize,
91        /// The verifier's reason.
92        reason: String,
93    },
94    /// `signPayout`: the signed transaction is bigger than the fee pays for.
95    #[error("the signed payout is {vsize} vB, so its fee of {fee} sat is below {rate} sat/vB; nothing was paid")]
96    FeeBelowRate {
97        /// The signed transaction's virtual size.
98        vsize: u64,
99        /// The plan's fee.
100        fee: u64,
101        /// The plan's rate.
102        rate: u64,
103    },
104    /// A key, point, tweak or scalar refused by the key rule
105    /// (`sidestr/spec siding/lib/keys.mjs`), in its words.
106    #[error("{0}")]
107    Key(&'static str),
108    /// Not a segwit script under that prefix (`address.mjs scriptToAddress`
109    /// returns `null`; this port refuses).
110    #[error("no address for that script under prefix {0:?}")]
111    Address(String),
112    /// A script or txid that is not hex of the right shape (this port: the
113    /// teller writes whatever it is given and the kernel's codec refuses it).
114    #[error("{what}: {reason}")]
115    Encoding {
116        /// Which field.
117        what: &'static str,
118        /// Why it was refused.
119        reason: String,
120    },
121    /// The chain's signature hash could not be computed for an input.
122    #[error("input {input}: {reason}")]
123    Sighash {
124        /// The input's index.
125        input: usize,
126        /// The reason the sighash refused.
127        reason: &'static str,
128    },
129    /// A Nostr event could not be built or signed (`sidestr-nostr`'s reason).
130    #[error("event: {0}")]
131    Event(String),
132    /// This port's reading of a ledger event (kind 30333), which the teller's
133    /// page does inline: not kind 30333.
134    #[error("not a ledger (kind 30333)")]
135    NotALedgerEvent,
136    /// This port: the ledger event's content is not a ledger document.
137    #[error("the ledger event's content is not a ledger: {0}")]
138    LedgerContent(String),
139    /// This port: a ledger event not signed by the ledger's operator, or for
140    /// another ledger (the page drops both: "the operator's own word only").
141    #[error("a ledger event that is not the operator's own copy of this ledger")]
142    NotTheOperators,
143}
144
145/// `Result` with this crate's [`Error`].
146pub type Result<T> = core::result::Result<T, Error>;