1#![deny(
28 unsafe_code,
29 dead_code,
30 unused_variables,
33 unused_mut,
34 unused_imports,
35 non_upper_case_globals,
36 non_camel_case_types,
37 non_snake_case
38)]
39#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
40#![cfg_attr(docsrs, feature(doc_auto_cfg))]
41
42#[macro_use]
43extern crate amplify;
44#[cfg(any(feature = "bitcoin", feature = "liquid"))]
45#[macro_use]
46extern crate strict_encoding;
47#[cfg(feature = "serde")]
48#[macro_use]
49extern crate serde;
50
51#[cfg(any(feature = "bitcoin", feature = "liquid"))]
52pub mod bp;
53
54use core::fmt::{self, Display, Formatter};
55use core::str::FromStr;
56
57use baid64::Baid64ParseError;
58use hypersonic::{AuthToken, Consensus};
59use sonic_callreq::{CallRequest, CallScope};
60
61pub type RgbInvoice<T = CallScope<ContractQuery>> = CallRequest<T, RgbBeneficiary>;
62
63#[derive(Clone, Eq, PartialEq, Debug, Display)]
64#[display(inner)]
65#[cfg_attr(
66 feature = "serde",
67 derive(Serialize, Deserialize),
68 serde(rename_all = "camelCase", untagged)
69)]
70pub enum RgbBeneficiary {
71 Token(AuthToken),
72
73 #[cfg(any(feature = "bitcoin", feature = "liquid"))]
74 WitnessOut(bp::WitnessOut),
75}
76
77impl FromStr for RgbBeneficiary {
78 type Err = ParseInvoiceError;
79
80 fn from_str(s: &str) -> Result<Self, Self::Err> {
81 match AuthToken::from_str(s) {
82 Ok(auth) => Ok(Self::Token(auth)),
83
84 #[cfg(any(feature = "bitcoin", feature = "liquid"))]
85 Err(_) => {
86 let wout = bp::WitnessOut::from_str(s)?;
87 Ok(Self::WitnessOut(wout))
88 }
89 #[cfg(not(any(feature = "bitcoin", feature = "liquid")))]
90 Err(err) => Err(err),
91 }
92 }
93}
94
95#[cfg(any(feature = "bitcoin", feature = "liquid"))]
96impl RgbBeneficiary {
97 pub fn witness_out(&self) -> Option<&bp::WitnessOut> {
98 match self {
99 Self::WitnessOut(wout) => Some(wout),
100 _ => None,
101 }
102 }
103}
104
105#[derive(Clone, Eq, PartialEq, Debug)]
106pub struct ContractQuery {
107 pub consensus: Consensus,
108 pub testnet: bool,
109}
110
111impl Display for ContractQuery {
112 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
113 if self.testnet {
114 f.write_str("testnet@")?;
115 }
116 Display::fmt(&self.consensus, f)
117 }
118}
119
120impl FromStr for ContractQuery {
121 type Err = String;
122
123 fn from_str(s: &str) -> Result<Self, Self::Err> {
124 let testnet = s.starts_with("testnet@");
125 let s = s.trim_start_matches("testnet@");
126 Consensus::from_str(s).map(|consensus| Self { consensus, testnet })
127 }
128}
129
130#[derive(Debug, Display, Error, From)]
131#[display(doc_comments)]
132pub enum ParseInvoiceError {
133 NoScheme,
135
136 Unrecognizable(Baid64ParseError),
139
140 #[cfg(any(feature = "bitcoin", feature = "liquid"))]
141 #[from]
142 Bp(bp::ParseWitnessOutError),
143}