1#![warn(
4 future_incompatible,
5 nonstandard_style,
6 rust_2018_idioms,
7 rust_2021_compatibility
8)]
9
10use base_types::{SequenceNumber, SuiAddress};
11use move_binary_format::CompiledModule;
12use move_binary_format::file_format::{AbilitySet, SignatureToken};
13use move_bytecode_utils::resolve_struct;
14use move_core_types::language_storage::ModuleId;
15use move_core_types::{account_address::AccountAddress, language_storage::StructTag};
16pub use move_core_types::{identifier::Identifier, language_storage::TypeTag};
17use object::OBJECT_START_VERSION;
18
19use base_types::ObjectID;
20
21pub use mysten_network::multiaddr;
22
23use crate::base_types::{RESOLVED_ASCII_STR, RESOLVED_UTF8_STR};
24use crate::{base_types::RESOLVED_STD_OPTION, id::RESOLVED_SUI_ID};
25
26#[macro_use]
27pub mod error;
28pub mod accumulator_event;
29pub mod accumulator_metadata;
30pub mod accumulator_root;
31pub mod address_alias;
32pub mod authenticator_state;
33pub mod balance;
34pub mod balance_change;
35pub mod base_types;
36pub mod bridge;
37pub mod clock;
38pub mod coin;
39pub mod coin_registry;
40pub mod coin_reservation;
41pub mod collection_types;
42pub mod committee;
43pub mod config;
44pub mod crypto;
45pub mod deny_list_v1;
46pub mod deny_list_v2;
47pub mod derived_object;
48pub mod digests;
49pub mod display;
50pub mod display_registry;
51pub mod dynamic_field;
52pub mod effects;
53pub mod epoch_data;
54pub mod event;
55pub mod executable_transaction;
56pub mod execution;
57pub mod execution_params;
58pub mod execution_status;
59pub mod full_checkpoint_content;
60pub mod funds_accumulator;
61pub mod gas;
62pub mod gas_coin;
63pub mod gas_model;
64pub mod global_state_hash;
65pub mod governance;
66pub mod id;
67pub mod in_memory_storage;
68pub mod inner_temporary_store;
69pub mod layout_resolver;
70pub mod message_envelope;
71pub mod messages_checkpoint;
72pub mod messages_consensus;
73pub mod messages_grpc;
74pub mod messages_safe_client;
75pub mod metrics;
76pub mod move_package;
77pub mod multisig;
78pub mod multisig_legacy;
79pub mod nitro_attestation;
80pub mod node_role;
81pub mod object;
82pub mod passkey_authenticator;
83pub mod programmable_transaction_builder;
84pub mod ptb_trace;
85pub mod randomness_state;
86pub mod rpc_proto_conversions;
87pub mod signature;
88pub mod signature_verification;
89pub mod storage;
90pub mod sui_sdk_types_conversions;
91pub mod sui_serde;
92pub mod sui_system_state;
93pub mod supported_protocol_versions;
94pub mod test_checkpoint_data_builder;
95pub mod traffic_control;
96pub mod transaction;
97pub mod transaction_deny_rules;
98pub mod transaction_driver_types;
99pub mod transaction_executor;
100pub mod transfer;
101pub mod type_input;
102pub mod versioned;
103pub mod zk_login_authenticator;
104pub mod zk_login_util;
105
106#[path = "./unit_tests/utils.rs"]
107pub mod utils;
108
109macro_rules! built_in_ids {
110 ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
111 $(
112 pub const $addr: AccountAddress = AccountAddress::from_suffix($init);
113 pub const $id: ObjectID = ObjectID::from_address($addr);
114 )*
115 }
116}
117
118macro_rules! built_in_pkgs {
119 ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
120 built_in_ids! { $($addr / $id = $init;)* }
121 pub const SYSTEM_PACKAGE_ADDRESSES: &[AccountAddress] = &[$($addr),*];
122 pub fn is_system_package(addr: impl Into<AccountAddress>) -> bool {
123 matches!(addr.into(), $($addr)|*)
124 }
125 }
126}
127
128built_in_pkgs! {
129 MOVE_STDLIB_ADDRESS / MOVE_STDLIB_PACKAGE_ID = 0x1;
130 SUI_FRAMEWORK_ADDRESS / SUI_FRAMEWORK_PACKAGE_ID = 0x2;
131 SUI_SYSTEM_ADDRESS / SUI_SYSTEM_PACKAGE_ID = 0x3;
132 BRIDGE_ADDRESS / BRIDGE_PACKAGE_ID = 0xb;
133 DEEPBOOK_ADDRESS / DEEPBOOK_PACKAGE_ID = 0xdee9;
134}
135
136built_in_ids! {
137 SUI_SYSTEM_STATE_ADDRESS / SUI_SYSTEM_STATE_OBJECT_ID = 0x5;
138 SUI_CLOCK_ADDRESS / SUI_CLOCK_OBJECT_ID = 0x6;
139 SUI_AUTHENTICATOR_STATE_ADDRESS / SUI_AUTHENTICATOR_STATE_OBJECT_ID = 0x7;
140 SUI_RANDOMNESS_STATE_ADDRESS / SUI_RANDOMNESS_STATE_OBJECT_ID = 0x8;
141 SUI_BRIDGE_ADDRESS / SUI_BRIDGE_OBJECT_ID = 0x9;
142 SUI_COIN_REGISTRY_ADDRESS / SUI_COIN_REGISTRY_OBJECT_ID = 0xc;
143 SUI_DISPLAY_REGISTRY_ADDRESS / SUI_DISPLAY_REGISTRY_OBJECT_ID = 0xd;
144 SUI_DENY_LIST_ADDRESS / SUI_DENY_LIST_OBJECT_ID = 0x403;
145 SUI_ACCUMULATOR_ROOT_ADDRESS / SUI_ACCUMULATOR_ROOT_OBJECT_ID = 0xacc;
146 SUI_ADDRESS_ALIAS_STATE_ADDRESS / SUI_ADDRESS_ALIAS_STATE_OBJECT_ID = 0xa;
147}
148
149pub const SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
150pub const SUI_CLOCK_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
151
152pub fn sui_framework_address_concat_string(suffix: &str) -> String {
153 format!("{}{suffix}", SUI_FRAMEWORK_ADDRESS.to_hex_literal())
154}
155
156pub fn parse_sui_address(s: &str) -> anyhow::Result<SuiAddress> {
164 use move_core_types::parsing::address::ParsedAddress;
165 Ok(ParsedAddress::parse(s)?
166 .into_account_address(&resolve_address)?
167 .into())
168}
169
170pub fn parse_sui_module_id(s: &str) -> anyhow::Result<ModuleId> {
174 use move_core_types::parsing::types::ParsedModuleId;
175 ParsedModuleId::parse(s)?.into_module_id(&resolve_address)
176}
177
178pub fn parse_sui_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> {
183 use move_core_types::parsing::types::ParsedFqName;
184 ParsedFqName::parse(s)?.into_fq_name(&resolve_address)
185}
186
187pub fn parse_sui_struct_tag(s: &str) -> anyhow::Result<StructTag> {
192 use move_core_types::parsing::types::ParsedStructType;
193 ParsedStructType::parse(s)?.into_struct_tag(&resolve_address)
194}
195
196pub fn parse_sui_type_tag(s: &str) -> anyhow::Result<TypeTag> {
200 use move_core_types::parsing::types::ParsedType;
201 ParsedType::parse(s)?.into_type_tag(&resolve_address)
202}
203
204pub fn resolve_address(addr: &str) -> Option<AccountAddress> {
206 match addr {
207 "deepbook" => Some(DEEPBOOK_ADDRESS),
208 "std" => Some(MOVE_STDLIB_ADDRESS),
209 "sui" => Some(SUI_FRAMEWORK_ADDRESS),
210 "sui_system" => Some(SUI_SYSTEM_ADDRESS),
211 "bridge" => Some(BRIDGE_ADDRESS),
212 _ => None,
213 }
214}
215
216pub trait MoveTypeTagTrait {
217 fn get_type_tag() -> TypeTag;
218
219 fn get_instance_type_tag(&self) -> TypeTag {
220 Self::get_type_tag()
221 }
222}
223
224impl MoveTypeTagTrait for u8 {
225 fn get_type_tag() -> TypeTag {
226 TypeTag::U8
227 }
228}
229
230impl MoveTypeTagTrait for u64 {
231 fn get_type_tag() -> TypeTag {
232 TypeTag::U64
233 }
234}
235
236impl MoveTypeTagTrait for ObjectID {
237 fn get_type_tag() -> TypeTag {
238 TypeTag::Address
239 }
240}
241
242impl MoveTypeTagTrait for SuiAddress {
243 fn get_type_tag() -> TypeTag {
244 TypeTag::Address
245 }
246}
247
248impl<T: MoveTypeTagTrait> MoveTypeTagTrait for Vec<T> {
249 fn get_type_tag() -> TypeTag {
250 TypeTag::Vector(Box::new(T::get_type_tag()))
251 }
252}
253
254pub trait MoveTypeTagTraitGeneric {
255 fn get_type_tag(type_params: &[TypeTag]) -> TypeTag;
256}
257
258pub fn is_primitive(
259 view: &CompiledModule,
260 function_type_args: &[AbilitySet],
261 s: &SignatureToken,
262) -> bool {
263 use SignatureToken as S;
264 match s {
265 S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true,
266 S::Signer => false,
267 S::TypeParameter(idx) => !function_type_args[*idx as usize].has_key(),
269
270 S::Datatype(idx) => [RESOLVED_SUI_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR]
271 .contains(&resolve_struct(view, *idx)),
272
273 S::DatatypeInstantiation(inst) => {
274 let (idx, targs) = &**inst;
275 let resolved_struct = resolve_struct(view, *idx);
276 resolved_struct == RESOLVED_STD_OPTION
278 && targs.len() == 1
279 && is_primitive(view, function_type_args, &targs[0])
280 }
281
282 S::Vector(inner) => is_primitive(view, function_type_args, inner),
283 S::Reference(_) | S::MutableReference(_) => false,
284 }
285}
286
287pub fn is_object(
288 view: &CompiledModule,
289 function_type_args: &[AbilitySet],
290 t: &SignatureToken,
291) -> Result<bool, String> {
292 use SignatureToken as S;
293 match t {
294 S::Reference(inner) | S::MutableReference(inner) => {
295 is_object(view, function_type_args, inner)
296 }
297 _ => is_object_struct(view, function_type_args, t),
298 }
299}
300
301pub fn is_object_vector(
302 view: &CompiledModule,
303 function_type_args: &[AbilitySet],
304 t: &SignatureToken,
305) -> Result<bool, String> {
306 use SignatureToken as S;
307 match t {
308 S::Vector(inner) => is_object_struct(view, function_type_args, inner),
309 _ => is_object_struct(view, function_type_args, t),
310 }
311}
312
313fn is_object_struct(
314 view: &CompiledModule,
315 function_type_args: &[AbilitySet],
316 s: &SignatureToken,
317) -> Result<bool, String> {
318 use SignatureToken as S;
319 match s {
320 S::Bool
321 | S::U8
322 | S::U16
323 | S::U32
324 | S::U64
325 | S::U128
326 | S::U256
327 | S::Address
328 | S::Signer
329 | S::Vector(_)
330 | S::Reference(_)
331 | S::MutableReference(_) => Ok(false),
332 S::TypeParameter(idx) => Ok(function_type_args
333 .get(*idx as usize)
334 .map(|abs| abs.has_key())
335 .unwrap_or(false)),
336 S::Datatype(_) | S::DatatypeInstantiation(_) => {
337 let abilities = view
338 .abilities(s, function_type_args)
339 .map_err(|vm_err| vm_err.to_string())?;
340 Ok(abilities.has_key())
341 }
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348 use expect_test::expect;
349
350 #[test]
351 fn test_parse_sui_numeric_address() {
352 let result = parse_sui_address("0x2").expect("should not error");
353
354 let expected =
355 expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
356 expected.assert_eq(&result.to_string());
357 }
358
359 #[test]
360 fn test_parse_sui_named_address() {
361 let result = parse_sui_address("sui").expect("should not error");
362
363 let expected =
364 expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
365 expected.assert_eq(&result.to_string());
366 }
367
368 #[test]
369 fn test_parse_sui_module_id() {
370 let result = parse_sui_module_id("0x2::sui").expect("should not error");
371 let expected =
372 expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui"];
373 expected.assert_eq(&result.to_canonical_string(true));
374 }
375
376 #[test]
377 fn test_parse_sui_fq_name() {
378 let (module, name) = parse_sui_fq_name("0x2::object::new").expect("should not error");
379 let expected = expect![
380 "0x0000000000000000000000000000000000000000000000000000000000000002::object::new"
381 ];
382 expected.assert_eq(&format!(
383 "{}::{name}",
384 module.to_canonical_display(true)
385 ));
386 }
387
388 #[test]
389 fn test_parse_sui_struct_tag_short_account_addr() {
390 let result = parse_sui_struct_tag("0x2::sui::SUI").expect("should not error");
391
392 let expected = expect!["0x2::sui::SUI"];
393 expected.assert_eq(&result.to_string());
394
395 let expected =
396 expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"];
397 expected.assert_eq(&result.to_canonical_string(true));
398 }
399
400 #[test]
401 fn test_parse_sui_struct_tag_long_account_addr() {
402 let result = parse_sui_struct_tag(
403 "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",
404 )
405 .expect("should not error");
406
407 let expected = expect!["0x2::sui::SUI"];
408 expected.assert_eq(&result.to_string());
409
410 let expected =
411 expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"];
412 expected.assert_eq(&result.to_canonical_string(true));
413 }
414
415 #[test]
416 fn test_parse_sui_struct_with_type_param_short_addr() {
417 let result =
418 parse_sui_struct_tag("0x2::coin::COIN<0x2::sui::SUI>").expect("should not error");
419
420 let expected = expect!["0x2::coin::COIN<0x2::sui::SUI>"];
421 expected.assert_eq(&result.to_string());
422
423 let expected = expect![
424 "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>"
425 ];
426 expected.assert_eq(&result.to_canonical_string(true));
427 }
428
429 #[test]
430 fn test_parse_sui_struct_with_type_param_long_addr() {
431 let result = parse_sui_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>")
432 .expect("should not error");
433
434 let expected = expect!["0x2::coin::COIN<0x2::sui::SUI>"];
435 expected.assert_eq(&result.to_string());
436
437 let expected = expect![
438 "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>"
439 ];
440 expected.assert_eq(&result.to_canonical_string(true));
441 }
442
443 #[test]
444 fn test_complex_struct_tag_with_short_addr() {
445 let result =
446 parse_sui_struct_tag("0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::sui::SUI>>>")
447 .expect("should not error");
448
449 let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::sui::SUI>>>"];
450 expected.assert_eq(&result.to_string());
451
452 let expected = expect![
453 "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>>"
454 ];
455 expected.assert_eq(&result.to_canonical_string(true));
456 }
457
458 #[test]
459 fn test_complex_struct_tag_with_long_addr() {
460 let result = parse_sui_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>>")
461 .expect("should not error");
462
463 let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::sui::SUI>>>"];
464 expected.assert_eq(&result.to_string());
465
466 let expected = expect![
467 "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>>"
468 ];
469 expected.assert_eq(&result.to_canonical_string(true));
470 }
471
472 #[test]
473 fn test_dynamic_field_short_addr() {
474 let result = parse_sui_struct_tag(
475 "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>",
476 )
477 .expect("should not error");
478
479 let expected = expect![
480 "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>"
481 ];
482 expected.assert_eq(&result.to_string());
483
484 let expected = expect![
485 "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x000000000000000000000000000000000000000000000000000000000000dee9::custodian_v2::Account<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
486 ];
487 expected.assert_eq(&result.to_canonical_string(true));
488 }
489
490 #[test]
491 fn test_dynamic_field_long_addr() {
492 let result = parse_sui_struct_tag(
493 "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>",
494 )
495 .expect("should not error");
496
497 let expected = expect![
498 "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>"
499 ];
500 expected.assert_eq(&result.to_string());
501
502 let expected = expect![
503 "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x000000000000000000000000000000000000000000000000000000000000dee9::custodian_v2::Account<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
504 ];
505 expected.assert_eq(&result.to_canonical_string(true));
506 }
507}