iota_types/
move_authenticator.rs1use std::collections::HashSet;
5
6use iota_protocol_config::ProtocolConfig;
7use iota_sdk_types::{Address, ObjectId, TypeTag, crypto::IntentMessage};
8pub use iota_sdk_types::{MoveAuthenticator, MoveAuthenticatorV1};
9use serde::Serialize;
10
11use crate::{
12 base_types::{ObjectRef, SequenceNumber},
13 digests::ObjectDigest,
14 error::{IotaError, IotaResult, UserInputError, UserInputResult},
15 signature::{AuthenticatorTrait, VerifyParams},
16 transaction::{CallArg, CallArgExt, InputObjectKind, SharedObjectRef},
17};
18
19mod move_authenticator_ext {
20 pub trait Sealed {}
21 impl Sealed for super::MoveAuthenticator {}
22 impl Sealed for super::MoveAuthenticatorV1 {}
23}
24
25pub trait MoveAuthenticatorExt: Sized + move_authenticator_ext::Sealed {
26 fn address(&self) -> Address;
29
30 fn call_args(&self) -> &[CallArg];
33
34 fn type_args(&self) -> &[TypeTag];
36
37 fn object_to_authenticate(&self) -> &CallArg;
39
40 fn object_to_authenticate_components(
41 &self,
42 ) -> UserInputResult<(ObjectId, Option<SequenceNumber>, Option<ObjectDigest>)>;
43
44 fn input_objects(&self) -> Vec<InputObjectKind>;
45
46 fn receiving_objects(&self) -> Vec<ObjectRef>;
47
48 fn shared_objects(&self) -> Vec<SharedObjectRef>;
49
50 fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult;
51}
52
53impl MoveAuthenticatorExt for MoveAuthenticator {
54 fn address(&self) -> Address {
55 match self {
56 Self::V1(v1) => v1.address(),
57 _ => unimplemented!(
58 "a new MoveAuthenticator enum variant was added and needs to be handled"
59 ),
60 }
61 }
62
63 fn call_args(&self) -> &[CallArg] {
64 match self {
65 Self::V1(v1) => v1.call_args(),
66 _ => unimplemented!(
67 "a new MoveAuthenticator enum variant was added and needs to be handled"
68 ),
69 }
70 }
71
72 fn type_args(&self) -> &[TypeTag] {
73 match self {
74 Self::V1(v1) => v1.type_args(),
75 _ => unimplemented!(
76 "a new MoveAuthenticator enum variant was added and needs to be handled"
77 ),
78 }
79 }
80
81 fn object_to_authenticate(&self) -> &CallArg {
82 match self {
83 Self::V1(v1) => v1.object_to_authenticate(),
84 _ => unimplemented!(
85 "a new MoveAuthenticator enum variant was added and needs to be handled"
86 ),
87 }
88 }
89
90 fn object_to_authenticate_components(
91 &self,
92 ) -> UserInputResult<(ObjectId, Option<SequenceNumber>, Option<ObjectDigest>)> {
93 match self {
94 Self::V1(v1) => v1.object_to_authenticate_components(),
95 _ => unimplemented!(
96 "a new MoveAuthenticator enum variant was added and needs to be handled"
97 ),
98 }
99 }
100
101 fn input_objects(&self) -> Vec<InputObjectKind> {
102 match self {
103 Self::V1(v1) => v1.input_objects(),
104 _ => unimplemented!(
105 "a new MoveAuthenticator enum variant was added and needs to be handled"
106 ),
107 }
108 }
109
110 fn receiving_objects(&self) -> Vec<ObjectRef> {
111 match self {
112 Self::V1(v1) => v1.receiving_objects(),
113 _ => unimplemented!(
114 "a new MoveAuthenticator enum variant was added and needs to be handled"
115 ),
116 }
117 }
118
119 fn shared_objects(&self) -> Vec<SharedObjectRef> {
120 match self {
121 Self::V1(v1) => v1.shared_objects(),
122 _ => unimplemented!(
123 "a new MoveAuthenticator enum variant was added and needs to be handled"
124 ),
125 }
126 }
127
128 fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
129 match self {
130 Self::V1(v1) => v1.validity_check(config),
131 _ => unimplemented!(
132 "a new MoveAuthenticator enum variant was added and needs to be handled"
133 ),
134 }
135 }
136}
137
138impl MoveAuthenticatorExt for MoveAuthenticatorV1 {
139 fn address(&self) -> Address {
142 self.address()
143 }
144
145 fn call_args(&self) -> &[CallArg] {
146 self.call_args()
147 }
148
149 fn type_args(&self) -> &[TypeTag] {
150 self.type_args()
151 }
152
153 fn object_to_authenticate(&self) -> &CallArg {
154 self.object_to_authenticate()
155 }
156
157 fn object_to_authenticate_components(
158 &self,
159 ) -> UserInputResult<(ObjectId, Option<SequenceNumber>, Option<ObjectDigest>)> {
160 Ok(match self.object_to_authenticate() {
161 CallArg::Pure(_) => {
162 return Err(UserInputError::Unsupported(
163 "MoveAuthenticatorV1 cannot authenticate pure inputs".to_string(),
164 ));
165 }
166 CallArg::ImmutableOrOwned(object_ref) => (
167 object_ref.object_id,
168 Some(object_ref.version),
169 Some(object_ref.digest),
170 ),
171 CallArg::Shared(SharedObjectRef {
172 object_id, mutable, ..
173 }) => {
174 if *mutable {
175 return Err(UserInputError::Unsupported(
176 "MoveAuthenticatorV1 cannot authenticate mutable shared objects"
177 .to_string(),
178 ));
179 }
180
181 (*object_id, None, None)
182 }
183 CallArg::Receiving(_) => {
184 return Err(UserInputError::Unsupported(
185 "MoveAuthenticator cannot authenticate receiving objects".to_string(),
186 ));
187 }
188 _ => unimplemented!("a new CallArg enum variant was added and needs to be handled"),
189 })
190 }
191
192 fn input_objects(&self) -> Vec<InputObjectKind> {
195 self.call_args()
196 .iter()
197 .filter_map(|arg| arg.input_object_kind())
198 .chain(self.object_to_authenticate().input_object_kind())
199 .collect::<Vec<_>>()
200 }
201
202 fn receiving_objects(&self) -> Vec<ObjectRef> {
203 self.call_args()
204 .iter()
205 .filter_map(|arg| arg.as_opt_receiving().copied())
206 .collect()
207 }
208
209 fn shared_objects(&self) -> Vec<SharedObjectRef> {
212 self.call_args()
213 .iter()
214 .filter_map(|arg| arg.as_opt_shared())
215 .chain(self.object_to_authenticate().as_opt_shared())
216 .cloned()
217 .collect()
218 }
219
220 fn validity_check(&self, config: &ProtocolConfig) -> UserInputResult {
222 self.object_to_authenticate_components()?;
224
225 let max_args = (config.max_function_parameters() - 3) as usize;
237 fp_ensure!(
238 self.call_args().len() < max_args,
239 UserInputError::SizeLimitExceeded {
240 limit: "maximum arguments in MoveAuthenticatorV1".to_string(),
241 value: max_args.to_string()
242 }
243 );
244
245 fp_ensure!(
246 self.receiving_objects().is_empty(),
247 UserInputError::Unsupported(
248 "MoveAuthenticatorV1 cannot have receiving objects as input".to_string(),
249 )
250 );
251
252 let mut used = HashSet::new();
253 fp_ensure!(
254 self.input_objects()
255 .iter()
256 .all(|o| used.insert(o.object_id())),
257 UserInputError::DuplicateObjectRefInput
258 );
259
260 self.call_args()
261 .iter()
262 .try_for_each(|obj| obj.validity_check(config))?;
263
264 let mut type_arguments_count = 0;
269 self.type_args().iter().try_for_each(|type_arg| {
270 crate::transaction::type_tag_validity_check(type_arg, config, &mut type_arguments_count)
271 })?;
272
273 Ok(())
274 }
275}
276
277impl AuthenticatorTrait for MoveAuthenticator {
278 fn verify_claims<T>(
281 &self,
282 value: &IntentMessage<T>,
283 author: Address,
284 aux_verify_data: &VerifyParams,
285 ) -> IotaResult
286 where
287 T: Serialize,
288 {
289 match self {
290 Self::V1(v1) => v1.verify_claims(value, author, aux_verify_data),
291 _ => unimplemented!(
292 "a new MoveAuthenticator enum variant was added and needs to be handled"
293 ),
294 }
295 }
296}
297
298impl AuthenticatorTrait for MoveAuthenticatorV1 {
299 fn verify_claims<T>(
302 &self,
303 _value: &IntentMessage<T>,
304 author: Address,
305 _aux_verify_data: &VerifyParams,
306 ) -> IotaResult
307 where
308 T: Serialize,
309 {
310 if author != self.address() {
311 return Err(IotaError::InvalidSignature {
312 error: "Invalid author".to_string(),
313 });
314 };
315
316 Ok(())
317 }
318}