1use crate::static_programmable_transactions::linkage::resolved_linkage::{
5 ResolvedLinkage, RootedLinkage,
6};
7use indexmap::IndexSet;
8use move_binary_format::file_format::{AbilitySet, CodeOffset, FunctionDefinitionIndex};
9use move_core_types::{
10 account_address::AccountAddress,
11 identifier::IdentStr,
12 language_storage::{ModuleId, StructTag},
13 u256::U256,
14};
15use std::rc::Rc;
16use sui_types::{
17 Identifier, TypeTag,
18 base_types::{ObjectID, ObjectRef, RESOLVED_TX_CONTEXT, SequenceNumber, TxContextKind},
19};
20
21#[derive(Debug)]
26pub struct Transaction {
27 pub inputs: Inputs,
28 pub commands: Commands,
29}
30
31pub type Inputs = Vec<(InputArg, InputType)>;
32
33pub type Commands = Vec<Command>;
34
35#[derive(Debug)]
36#[cfg_attr(debug_assertions, derive(Clone))]
37pub enum InputArg {
38 Pure(Vec<u8>),
39 Receiving(ObjectRef),
40 Object(ObjectArg),
41 FundsWithdrawal(FundsWithdrawalArg),
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum SharedObjectKind {
46 Legacy,
47 Party,
48}
49
50#[derive(Debug)]
51#[cfg_attr(debug_assertions, derive(Clone))]
52pub enum ObjectArg {
53 ImmObject(ObjectRef),
54 OwnedObject(ObjectRef),
55 SharedObject {
56 id: ObjectID,
57 initial_shared_version: SequenceNumber,
58 mutability: ObjectMutability,
59 kind: SharedObjectKind,
60 },
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum ObjectMutability {
65 Mutable,
66 Immutable,
67 NonExclusiveWrite,
68}
69
70#[derive(Debug)]
71#[cfg_attr(debug_assertions, derive(Clone))]
72pub struct FundsWithdrawalArg {
73 pub ty: Type,
75 pub owner: AccountAddress,
76 pub amount: U256,
78}
79
80#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
81pub enum Type {
82 Bool,
83 U8,
84 U16,
85 U32,
86 U64,
87 U128,
88 U256,
89 Address,
90 Signer,
91 Vector(Rc<Vector>),
92 Datatype(Rc<Datatype>),
93 Reference(bool, Rc<Type>),
94}
95
96#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
97pub struct Vector {
98 pub abilities: AbilitySet,
99 pub element_type: Type,
100}
101
102#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
103pub struct Datatype {
104 pub abilities: AbilitySet,
105 pub module: ModuleId,
106 pub name: Identifier,
107 pub type_arguments: Vec<Type>,
108}
109
110#[derive(Debug, Clone)]
111pub enum InputType {
112 Bytes,
113 Fixed(Type),
114}
115
116#[derive(Debug)]
117pub enum Command {
118 MoveCall(Box<MoveCall>),
119 TransferObjects(Vec<Argument>, Argument),
120 SplitCoins(Argument, Vec<Argument>),
121 MergeCoins(Argument, Vec<Argument>),
122 MakeMoveVec(Option<Type>, Vec<Argument>),
123 Publish(Vec<Vec<u8>>, Vec<ObjectID>, ResolvedLinkage),
124 Upgrade(
125 Vec<Vec<u8>>,
126 Vec<ObjectID>,
127 ObjectID,
128 Argument,
129 ResolvedLinkage,
130 ),
131}
132
133#[derive(Debug)]
134pub struct LoadedFunctionInstantiation {
135 pub parameters: Vec<Type>,
136 pub return_: Vec<Type>,
137}
138
139#[derive(Debug)]
140pub struct LoadedFunction {
141 pub storage_id: ModuleId,
142 pub runtime_id: ModuleId,
143 pub name: Identifier,
144 pub type_arguments: Vec<Type>,
145 pub signature: LoadedFunctionInstantiation,
146 pub linkage: RootedLinkage,
147 pub instruction_length: CodeOffset,
148 pub definition_index: FunctionDefinitionIndex,
149}
150
151#[derive(Debug)]
152pub struct MoveCall {
153 pub function: LoadedFunction,
154 pub arguments: Vec<Argument>,
155}
156
157pub use sui_types::transaction::Argument;
158
159impl ObjectArg {
164 pub fn id(&self) -> ObjectID {
165 match self {
166 ObjectArg::ImmObject(oref) | ObjectArg::OwnedObject(oref) => oref.0,
167 ObjectArg::SharedObject { id, .. } => *id,
168 }
169 }
170
171 pub fn mutability(&self) -> ObjectMutability {
172 match self {
173 ObjectArg::ImmObject(_) => ObjectMutability::Immutable,
174 ObjectArg::OwnedObject(_) => ObjectMutability::Mutable,
175 ObjectArg::SharedObject { mutability, .. } => *mutability,
176 }
177 }
178}
179
180impl Type {
181 pub fn abilities(&self) -> AbilitySet {
182 match self {
183 Type::Bool
184 | Type::U8
185 | Type::U16
186 | Type::U32
187 | Type::U64
188 | Type::U128
189 | Type::U256
190 | Type::Address => AbilitySet::PRIMITIVES,
191 Type::Signer => AbilitySet::SIGNER,
192 Type::Reference(_, _) => AbilitySet::REFERENCES,
193 Type::Vector(v) => v.abilities,
194 Type::Datatype(dt) => dt.abilities,
195 }
196 }
197
198 pub fn is_tx_context(&self) -> TxContextKind {
199 let (is_mut, inner) = match self {
200 Type::Reference(is_mut, inner) => (*is_mut, inner),
201 _ => return TxContextKind::None,
202 };
203 let Type::Datatype(dt) = &**inner else {
204 return TxContextKind::None;
205 };
206 if dt.qualified_ident() == RESOLVED_TX_CONTEXT {
207 if is_mut {
208 TxContextKind::Mutable
209 } else {
210 TxContextKind::Immutable
211 }
212 } else {
213 TxContextKind::None
214 }
215 }
216 pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
217 match self {
218 Type::Bool
219 | Type::U8
220 | Type::U16
221 | Type::U32
222 | Type::U64
223 | Type::U128
224 | Type::U256
225 | Type::Address
226 | Type::Signer => IndexSet::new(),
227 Type::Vector(v) => v.element_type.all_addresses(),
228 Type::Reference(_, inner) => inner.all_addresses(),
229 Type::Datatype(dt) => dt.all_addresses(),
230 }
231 }
232
233 pub fn node_count(&self) -> u64 {
234 use Type::*;
235 let mut total = 0u64;
236 let mut stack = vec![self];
237
238 while let Some(ty) = stack.pop() {
239 total = total.saturating_add(1);
240 match ty {
241 Bool | U8 | U16 | U32 | U64 | U128 | U256 | Address | Signer => {}
242 Vector(v) => stack.push(&v.element_type),
243 Reference(_, inner) => stack.push(inner),
244 Datatype(dt) => {
245 stack.extend(&dt.type_arguments);
246 }
247 }
248 }
249
250 total
251 }
252
253 pub fn is_reference(&self) -> bool {
254 match self {
255 Type::Bool
256 | Type::U8
257 | Type::U16
258 | Type::U32
259 | Type::U64
260 | Type::U128
261 | Type::U256
262 | Type::Address
263 | Type::Signer
264 | Type::Vector(_)
265 | Type::Datatype(_) => false,
266 Type::Reference(_, _) => true,
267 }
268 }
269}
270
271impl Datatype {
272 pub fn qualified_ident(&self) -> (&AccountAddress, &IdentStr, &IdentStr) {
273 (
274 self.module.address(),
275 self.module.name(),
276 self.name.as_ident_str(),
277 )
278 }
279
280 pub fn all_addresses(&self) -> IndexSet<AccountAddress> {
281 let mut addresses = IndexSet::new();
282 addresses.insert(*self.module.address());
283 for arg in &self.type_arguments {
284 addresses.extend(arg.all_addresses());
285 }
286 addresses
287 }
288}
289
290impl TryFrom<Type> for TypeTag {
295 type Error = &'static str;
296 fn try_from(ty: Type) -> Result<Self, Self::Error> {
297 Ok(match ty {
298 Type::Bool => TypeTag::Bool,
299 Type::U8 => TypeTag::U8,
300 Type::U16 => TypeTag::U16,
301 Type::U32 => TypeTag::U32,
302 Type::U64 => TypeTag::U64,
303 Type::U128 => TypeTag::U128,
304 Type::U256 => TypeTag::U256,
305 Type::Address => TypeTag::Address,
306 Type::Signer => TypeTag::Signer,
307 Type::Vector(inner) => {
308 let Vector { element_type, .. } = &*inner;
309 TypeTag::Vector(Box::new(element_type.clone().try_into()?))
310 }
311 Type::Datatype(dt) => {
312 let dt: &Datatype = &dt;
313 TypeTag::Struct(Box::new(dt.try_into()?))
314 }
315 Type::Reference(_, _) => return Err("unexpected reference type"),
316 })
317 }
318}
319
320impl TryFrom<&Datatype> for StructTag {
321 type Error = &'static str;
322
323 fn try_from(dt: &Datatype) -> Result<Self, Self::Error> {
324 let Datatype {
325 module,
326 name,
327 type_arguments,
328 ..
329 } = dt;
330 Ok(StructTag {
331 address: *module.address(),
332 module: module.name().to_owned(),
333 name: name.to_owned(),
334 type_params: type_arguments
335 .iter()
336 .map(|t| t.clone().try_into())
337 .collect::<Result<Vec<TypeTag>, _>>()?,
338 })
339 }
340}
341
342#[test]
347fn enum_size() {
348 assert_eq!(std::mem::size_of::<Type>(), 16);
349}