1use miden_protocol::Word;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum ProcedureName {
10 UpdateSigners,
11 UpdateProcedureThreshold,
12 AuthTx,
13 UpdateGuardian,
14 VerifyGuardian,
15 SendAsset,
16 ReceiveAsset,
17}
18
19impl ProcedureName {
20 pub fn root(&self) -> Word {
24 match self {
25 ProcedureName::UpdateSigners => procedure_root_word(
26 "0x34963b067dbba634e57b416bc2f2a9a8d4ac24147f40b2900148c9ba44774274",
27 ),
28 ProcedureName::UpdateProcedureThreshold => procedure_root_word(
29 "0xec74c4b96ce593c11017ae54dec9c0ae5e0d242e8b3074eb3908d961300aed67",
30 ),
31 ProcedureName::AuthTx => procedure_root_word(
32 "0x0708020dce7b91b61116e3eb27e5d686e129a83df3c540e0a7693b4523814e72",
33 ),
34 ProcedureName::UpdateGuardian => procedure_root_word(
35 "0xeceb1f2c2d7d20312dbaf091e9a27a2b63f9fcba120948043069793a5715bc96",
36 ),
37 ProcedureName::VerifyGuardian => procedure_root_word(
38 "0xe6a8a62d37117f55a79b5345aa3d263ab16e973d486bac9a1612663dfdecf82d",
39 ),
40 ProcedureName::SendAsset => procedure_root_word(
41 "0xfb1c73d10de1954e9e8948964e3e77cf4e33759d2e012cb00eb10c50f2974eb4",
42 ),
43 ProcedureName::ReceiveAsset => procedure_root_word(
44 "0x6170fd6d682d91777b551fd866258f43cc657f1291f8f071500f4e56e9c153da",
45 ),
46 }
47 }
48
49 pub fn all() -> &'static [ProcedureName] {
51 &[
52 ProcedureName::UpdateSigners,
53 ProcedureName::UpdateProcedureThreshold,
54 ProcedureName::AuthTx,
55 ProcedureName::UpdateGuardian,
56 ProcedureName::VerifyGuardian,
57 ProcedureName::SendAsset,
58 ProcedureName::ReceiveAsset,
59 ]
60 }
61}
62
63#[derive(Debug, Clone, Copy)]
76pub struct ProcedureThreshold {
77 pub procedure: ProcedureName,
78 pub threshold: u32,
79}
80
81impl ProcedureThreshold {
82 pub fn new(procedure: ProcedureName, threshold: u32) -> Self {
83 Self {
84 procedure,
85 threshold,
86 }
87 }
88
89 pub fn procedure_root(&self) -> Word {
90 self.procedure.root()
91 }
92}
93
94impl std::fmt::Display for ProcedureName {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 match self {
97 ProcedureName::UpdateSigners => write!(f, "update_signers"),
98 ProcedureName::UpdateProcedureThreshold => write!(f, "update_procedure_threshold"),
99 ProcedureName::AuthTx => write!(f, "auth_tx"),
100 ProcedureName::UpdateGuardian => write!(f, "update_guardian"),
101 ProcedureName::VerifyGuardian => write!(f, "verify_guardian"),
102 ProcedureName::SendAsset => write!(f, "send_asset"),
103 ProcedureName::ReceiveAsset => write!(f, "receive_asset"),
104 }
105 }
106}
107
108impl std::str::FromStr for ProcedureName {
109 type Err = String;
110
111 fn from_str(s: &str) -> Result<Self, Self::Err> {
112 match s {
113 "update_signers" => Ok(ProcedureName::UpdateSigners),
114 "update_procedure_threshold" => Ok(ProcedureName::UpdateProcedureThreshold),
115 "auth_tx" => Ok(ProcedureName::AuthTx),
116 "update_guardian" => Ok(ProcedureName::UpdateGuardian),
117 "verify_guardian" => Ok(ProcedureName::VerifyGuardian),
118 "send_asset" => Ok(ProcedureName::SendAsset),
119 "receive_asset" => Ok(ProcedureName::ReceiveAsset),
120 _ => Err(format!("unknown procedure name: {}", s)),
121 }
122 }
123}
124
125fn procedure_root_word(hex_str: &str) -> Word {
126 Word::parse(hex_str).expect("valid procedure root constant")
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn procedure_roots_match_compiled_account() {
135 use miden_confidential_contracts::multisig_guardian::{
136 MultisigGuardianBuilder, MultisigGuardianConfig,
137 };
138 use miden_protocol::{Felt, Word};
139
140 let commit = |s: u64| {
141 Word::from([
142 Felt::new_unchecked(s),
143 Felt::new_unchecked(s + 1),
144 Felt::new_unchecked(s + 2),
145 Felt::new_unchecked(s + 3),
146 ])
147 };
148 let config = MultisigGuardianConfig::new(1, vec![commit(1)], commit(10));
149 let account = MultisigGuardianBuilder::new(config)
150 .with_seed([42u8; 32])
151 .build()
152 .expect("build account");
153
154 let roots: Vec<Word> = account
155 .code()
156 .procedures()
157 .iter()
158 .map(|p| *p.mast_root())
159 .collect();
160
161 assert_eq!(
162 ProcedureName::UpdateSigners.root(),
163 roots[0],
164 "update_signers"
165 );
166 assert_eq!(
167 ProcedureName::UpdateProcedureThreshold.root(),
168 roots[1],
169 "update_procedure_threshold"
170 );
171 assert_eq!(
172 ProcedureName::UpdateGuardian.root(),
173 roots[2],
174 "update_guardian"
175 );
176 assert_eq!(ProcedureName::AuthTx.root(), roots[3], "auth_tx");
177 assert_eq!(
178 ProcedureName::VerifyGuardian.root(),
179 roots[4],
180 "verify_guardian"
181 );
182 assert_eq!(ProcedureName::SendAsset.root(), roots[5], "send_asset");
183 assert_eq!(
184 ProcedureName::ReceiveAsset.root(),
185 roots[6],
186 "receive_asset"
187 );
188 }
189
190 #[test]
191 fn procedure_threshold_new_creates_correctly() {
192 let threshold = ProcedureThreshold::new(ProcedureName::ReceiveAsset, 1);
193 assert_eq!(threshold.procedure, ProcedureName::ReceiveAsset);
194 assert_eq!(threshold.threshold, 1);
195 }
196
197 #[test]
198 fn procedure_threshold_procedure_root_returns_correct_root() {
199 let threshold = ProcedureThreshold::new(ProcedureName::SendAsset, 2);
200 assert_eq!(threshold.procedure_root(), ProcedureName::SendAsset.root());
201 }
202
203 #[test]
204 fn procedure_name_round_trip() {
205 for name in ProcedureName::all() {
206 let s = name.to_string();
207 let parsed: ProcedureName = s.parse().unwrap();
208 assert_eq!(*name, parsed);
209 }
210 }
211
212 #[test]
213 fn procedure_roots_are_valid() {
214 for name in ProcedureName::all() {
215 let _root = name.root();
216 }
217 }
218
219 #[test]
220 fn parse_unknown_returns_error() {
221 let result: Result<ProcedureName, _> = "unknown_proc".parse();
222 assert!(result.is_err());
223 }
224}