elements_miniscript/extensions/
param.rs1use std::{fmt, hash};
4
5use elements::confidential;
6use elements::encode::serialize;
7use elements::hex::ToHex;
8
9use super::csfs::{CsfsKey, CsfsMsg};
10use super::introspect_ops::Spk;
11use super::CovenantExt;
12use crate::{Error, ExtTranslator};
13
14pub trait ArgFromStr: Sized {
23 fn arg_from_str(s: &str, parent: &str, pos: usize) -> Result<Self, Error>;
25}
26
27pub trait ExtParam: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash + ArgFromStr {}
29
30impl<T> ExtParam for T where
31 T: Clone + Eq + Ord + fmt::Debug + fmt::Display + hash::Hash + ArgFromStr
32{
33}
34
35impl ArgFromStr for String {
36 fn arg_from_str(s: &str, _parent: &str, _pos: usize) -> Result<Self, Error> {
37 Ok(String::from(s))
40 }
41}
42
43#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
46pub enum NoExtParam {}
47
48impl fmt::Display for NoExtParam {
49 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match *self {}
51 }
52}
53
54impl ArgFromStr for NoExtParam {
55 fn arg_from_str(_s: &str, _parent: &str, _pos: usize) -> Result<Self, Error> {
56 unreachable!("Called ArgFromStr for NoExt")
58 }
59}
60
61#[derive(Debug, PartialEq, Eq, Clone, Hash)]
63pub enum CovExtArgs {
64 XOnlyKey(CsfsKey),
66 CsfsMsg(CsfsMsg),
68 Asset(confidential::Asset),
70 Value(confidential::Value),
72 Script(Spk),
74}
75
76impl From<CsfsMsg> for CovExtArgs {
77 fn from(v: CsfsMsg) -> Self {
78 Self::CsfsMsg(v)
79 }
80}
81
82impl From<Spk> for CovExtArgs {
83 fn from(v: Spk) -> Self {
84 Self::Script(v)
85 }
86}
87
88impl From<confidential::Value> for CovExtArgs {
89 fn from(v: confidential::Value) -> Self {
90 Self::Value(v)
91 }
92}
93
94impl From<confidential::Asset> for CovExtArgs {
95 fn from(v: confidential::Asset) -> Self {
96 Self::Asset(v)
97 }
98}
99
100impl From<CsfsKey> for CovExtArgs {
101 fn from(v: CsfsKey) -> Self {
102 Self::XOnlyKey(v)
103 }
104}
105
106impl CovExtArgs {
107 pub fn csfs_key(key: bitcoin::key::XOnlyPublicKey) -> Self {
109 CovExtArgs::XOnlyKey(CsfsKey(key))
110 }
111
112 pub fn csfs_msg(msg: elements::secp256k1_zkp::Message) -> Self {
114 CovExtArgs::CsfsMsg(CsfsMsg::new(msg.as_ref().to_vec()).expect("32 byte size message"))
115 }
116
117 pub fn asset(asset: confidential::Asset) -> Self {
119 Self::from(asset)
120 }
121
122 pub fn value(value: confidential::Value) -> Self {
124 Self::from(value)
125 }
126
127 pub fn spk(spk: elements::Script) -> Self {
129 Self::from(Spk::new(spk))
130 }
131}
132
133impl PartialOrd for CovExtArgs {
134 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
135 Some(self.cmp(other))
136 }
137}
138
139impl Ord for CovExtArgs {
140 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
141 self.to_string().cmp(&other.to_string())
144 }
145}
146
147impl fmt::Display for CovExtArgs {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 match self {
150 CovExtArgs::XOnlyKey(x) => write!(f, "{}", x),
151 CovExtArgs::CsfsMsg(m) => write!(f, "{}", m),
152 CovExtArgs::Asset(a) => write!(f, "{}", serialize(a).to_hex()),
153 CovExtArgs::Value(v) => write!(f, "{}", serialize(v).to_hex()),
154 CovExtArgs::Script(s) => write!(f, "{}", s),
155 }
156 }
157}
158
159impl ArgFromStr for CovExtArgs {
160 fn arg_from_str(s: &str, parent: &str, pos: usize) -> Result<Self, Error> {
161 let arg = match (parent, pos) {
162 ("csfs", 0) => CovExtArgs::XOnlyKey(CsfsKey::arg_from_str(s, parent, pos)?),
163 ("csfs", 1) => CovExtArgs::CsfsMsg(CsfsMsg::arg_from_str(s, parent, pos)?),
164 ("asset_eq", 0) | ("asset_eq", 1) | ("is_exp_asset", 0) => {
165 CovExtArgs::Asset(confidential::Asset::arg_from_str(s, parent, pos)?)
166 }
167 ("value_eq", 0) | ("value_eq", 1) | ("is_exp_value", 0) => {
168 CovExtArgs::Value(confidential::Value::arg_from_str(s, parent, pos)?)
169 }
170 ("spk_eq", 0) | ("spk_eq", 1) => CovExtArgs::Script(Spk::arg_from_str(s, parent, pos)?),
171 _ => return Err(Error::Unexpected(s.to_string())),
172 };
173 Ok(arg)
174 }
175}
176
177pub trait ExtParamTranslator<PArg, QArg, E>
179where
180 PArg: ExtParam,
181 QArg: ExtParam,
182{
183 fn ext(&mut self, e: &PArg) -> Result<QArg, E>;
185}
186
187impl<T, PArg, QArg, E> ExtTranslator<CovenantExt<PArg>, CovenantExt<QArg>, E> for T
189where
190 T: ExtParamTranslator<PArg, QArg, E>,
191 PArg: ExtParam,
192 QArg: ExtParam,
193{
194 fn ext(&mut self, cov: &CovenantExt<PArg>) -> Result<CovenantExt<QArg>, E> {
196 match *cov {
197 CovenantExt::LegacyVerEq(ref v) => Ok(CovenantExt::LegacyVerEq(*v)),
198 CovenantExt::LegacyOutputsPref(ref p) => Ok(CovenantExt::LegacyOutputsPref(p.clone())),
199 CovenantExt::Csfs(ref c) => Ok(CovenantExt::Csfs(TranslateExtParam::translate_ext(
200 c, self,
201 )?)),
202 CovenantExt::Arith(ref e) => Ok(CovenantExt::Arith(TranslateExtParam::translate_ext(
203 e, self,
204 )?)),
205 CovenantExt::Introspect(ref c) => Ok(CovenantExt::Introspect(
206 TranslateExtParam::translate_ext(c, self)?,
207 )),
208 }
209 }
210}
211
212pub trait TranslateExtParam<PArg, QArg>
215where
216 PArg: ExtParam,
217 QArg: ExtParam,
218{
219 type Output;
221
222 fn translate_ext<T, E>(&self, translator: &mut T) -> Result<Self::Output, E>
225 where
226 T: ExtParamTranslator<PArg, QArg, E>;
227}