iota_types/auth_context/
mod.rs1mod fields_v1;
5
6pub use fields_v1::*;
7use move_binary_format::{CompiledModule, file_format::SignatureToken};
8use move_bytecode_utils::resolve_struct;
9use move_core_types::{
10 account_address::AccountAddress, ident_str, identifier::IdentStr, language_storage::StructTag,
11};
12use serde::Serialize;
13
14use crate::{
15 IOTA_FRAMEWORK_ADDRESS, digests::MoveAuthenticatorDigest, transaction::ProgrammableTransaction,
16};
17
18pub const AUTH_CONTEXT_MODULE_NAME: &IdentStr = ident_str!("auth_context");
19pub const AUTH_CONTEXT_STRUCT_NAME: &IdentStr = ident_str!("AuthContext");
20
21#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
47pub struct AuthContext {
48 auth_digest: MoveAuthenticatorDigest,
50 tx_inputs: Vec<MoveCallArg>,
52 tx_commands: Vec<MoveCommand>,
54}
55
56impl AuthContext {
57 pub fn new_from_components(
58 auth_digest: MoveAuthenticatorDigest,
59 ptb: &ProgrammableTransaction,
60 ) -> Self {
61 Self {
62 auth_digest,
63 tx_inputs: ptb.inputs.iter().map(MoveCallArg::from).collect(),
64 tx_commands: ptb.commands.iter().map(MoveCommand::from).collect(),
65 }
66 }
67
68 pub fn new_for_testing() -> Self {
69 Self {
70 auth_digest: MoveAuthenticatorDigest::default(),
71 tx_inputs: Vec::new(),
72 tx_commands: Vec::new(),
73 }
74 }
75
76 pub fn digest(&self) -> &MoveAuthenticatorDigest {
77 &self.auth_digest
78 }
79
80 pub fn tx_inputs(&self) -> &Vec<MoveCallArg> {
81 &self.tx_inputs
82 }
83
84 pub fn tx_commands(&self) -> &Vec<MoveCommand> {
85 &self.tx_commands
86 }
87
88 pub fn to_bcs_bytes(&self) -> Vec<u8> {
89 bcs::to_bytes(&self).unwrap()
90 }
91
92 pub fn to_move_bcs_bytes(&self) -> Vec<u8> {
93 bcs::to_bytes(&MoveAuthContext::default()).unwrap()
94 }
95
96 pub fn kind(module: &CompiledModule, token: &SignatureToken) -> AuthContextKind {
99 use SignatureToken as S;
100
101 let (kind, token) = match token {
102 S::MutableReference(token) => (AuthContextKind::Mutable, token),
103 S::Reference(token) => (AuthContextKind::Immutable, token),
104 _ => return AuthContextKind::None,
105 };
106
107 let S::Datatype(idx) = &**token else {
108 return AuthContextKind::None;
109 };
110
111 let (module_addr, module_name, struct_name) = resolve_struct(module, *idx);
112
113 if is_auth_context(module_addr, module_name, struct_name) {
114 kind
115 } else {
116 AuthContextKind::None
117 }
118 }
119
120 pub fn type_() -> StructTag {
121 StructTag {
122 address: IOTA_FRAMEWORK_ADDRESS,
123 module: AUTH_CONTEXT_MODULE_NAME.to_owned(),
124 name: AUTH_CONTEXT_STRUCT_NAME.to_owned(),
125 type_params: vec![],
126 }
127 }
128
129 pub fn replace(
133 &mut self,
134 auth_digest: MoveAuthenticatorDigest,
135 tx_inputs: Vec<MoveCallArg>,
136 tx_commands: Vec<MoveCommand>,
137 ) {
138 self.auth_digest = auth_digest;
139 self.tx_inputs = tx_inputs;
140 self.tx_commands = tx_commands;
141 }
142}
143
144#[derive(Default, Serialize)]
148pub struct MoveAuthContext {
149 auth_digest: MoveAuthenticatorDigest,
150 tx_inputs: Vec<MoveCallArg>,
151 tx_commands: Vec<MoveCommand>,
152}
153
154#[derive(PartialEq, Eq, Clone, Copy)]
155pub enum AuthContextKind {
156 None,
158 Mutable,
160 Immutable,
162}
163
164pub fn is_auth_context(
165 module_addr: &AccountAddress,
166 module_name: &IdentStr,
167 struct_name: &IdentStr,
168) -> bool {
169 module_addr == &IOTA_FRAMEWORK_ADDRESS
170 && module_name == AUTH_CONTEXT_MODULE_NAME
171 && struct_name == AUTH_CONTEXT_STRUCT_NAME
172}
173
174#[cfg(test)]
175mod tests {
176
177 use super::*;
178 use crate::{
179 base_types::ObjectID,
180 transaction::{Argument, CallArg, Command, ProgrammableMoveCall, ProgrammableTransaction},
181 type_input::{TypeInput, TypeName},
182 };
183
184 #[test]
185 fn auth_context_new_from_components() {
186 let ptb = ProgrammableTransaction {
187 inputs: vec![CallArg::Pure(vec![0xab])],
188 commands: vec![Command::MoveCall(Box::new(ProgrammableMoveCall {
189 package: ObjectID::from_hex_literal("0x0000000000000000000000000000000000000001")
190 .unwrap(),
191 module: "mod".to_string(),
192 function: "fun".to_string(),
193 type_arguments: vec![TypeInput::U8],
194 arguments: vec![Argument::GasCoin],
195 }))],
196 };
197
198 let ctx = AuthContext::new_from_components(MoveAuthenticatorDigest::default(), &ptb);
199
200 assert_eq!(ctx.tx_inputs().len(), 1);
201 assert_eq!(ctx.tx_commands().len(), 1);
202
203 assert!(matches!(ctx.tx_inputs()[0], MoveCallArg::Pure(_)));
204
205 let MoveCommand::MoveCall(call) = &ctx.tx_commands()[0] else {
207 panic!("expected MoveCall");
208 };
209 assert_eq!(
210 call.type_arguments,
211 vec![TypeName {
212 name: "u8".to_string()
213 }]
214 );
215 }
216
217 #[test]
218 fn auth_context_to_bcs_bytes_is_deterministic() {
219 let ctx = AuthContext::new_for_testing();
220 assert_eq!(ctx.to_bcs_bytes(), ctx.to_bcs_bytes());
221 }
222
223 #[test]
224 fn auth_context_to_bcs_bytes_reflects_content() {
225 let mut ctx = AuthContext::new_for_testing();
226 let empty_bytes = ctx.to_bcs_bytes();
227
228 ctx.replace(
229 MoveAuthenticatorDigest::default(),
230 vec![MoveCallArg::Pure(vec![1])],
231 vec![],
232 );
233 let non_empty_bytes = ctx.to_bcs_bytes();
234
235 assert_ne!(empty_bytes, non_empty_bytes);
236 }
237}