1#![warn(
6 future_incompatible,
7 nonstandard_style,
8 rust_2018_idioms,
9 rust_2021_compatibility
10)]
11
12use iota_sdk_types::{Address, ObjectId, StructTag, TypeTag, Version};
13use move_binary_format::{
14 CompiledModule,
15 file_format::{AbilitySet, SignatureToken},
16};
17use move_bytecode_utils::resolve_struct;
18use move_core_types::{account_address::AccountAddress, language_storage::ModuleId};
19use object::OBJECT_START_VERSION;
20
21use crate::{
22 base_types::{RESOLVED_ASCII_STR, RESOLVED_IOTA_ID, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR},
23 iota_sdk_types_conversions::{struct_tag_core_to_sdk, type_tag_core_to_sdk},
24};
25
26#[macro_use]
27pub mod error;
28
29pub mod account_abstraction;
30pub mod attestation;
31pub mod auth_context;
32pub mod balance;
33pub mod base_types;
34pub mod clock;
35pub mod coin;
36pub mod coin_manager;
37pub mod committee;
38pub mod config;
39pub mod crypto;
40pub mod deny_list_v1;
41pub mod deny_rule_governance;
42pub mod digests;
43pub mod dynamic_field;
44pub mod effects;
45pub mod epoch_data;
46pub mod event;
47pub mod executable_transaction;
48pub mod execution;
49pub mod execution_config_utils;
50pub mod full_checkpoint_content;
51pub mod gas;
52pub mod gas_coin;
53pub mod gas_model;
54pub mod global_state_hash;
55pub mod governance;
56pub mod in_memory_storage;
57pub mod inner_temporary_store;
58pub mod iota_sdk_types_conversions;
59pub mod iota_serde;
60pub mod iota_system_state;
61pub mod layout_resolver;
62pub mod message_envelope;
63pub mod messages_checkpoint;
64#[cfg(not(target_arch = "wasm32"))]
67pub mod messages_consensus;
68#[cfg(not(target_arch = "wasm32"))]
69pub mod messages_grpc;
70pub mod messages_safe_client;
71pub mod metrics;
72pub mod mock_checkpoint_builder;
73pub mod move_authenticator;
74pub mod move_layout;
75pub mod move_package;
76pub mod multisig;
77pub mod object;
78pub mod passkey_authenticator;
79pub mod programmable_transaction_builder;
80pub mod proto_value;
81pub mod ptb_trace;
82pub mod quorum_driver_types;
83pub mod randomness_state;
84pub mod signature;
85pub mod signature_verification;
86pub mod stardust;
87pub mod storage;
88pub mod supported_protocol_versions;
89pub mod test_checkpoint_data_builder;
90pub mod timelock;
91pub mod traffic_control;
92pub mod transaction;
93pub mod transaction_deny_rules;
94pub mod transaction_driver_types;
95pub mod transaction_executor;
96pub mod transfer;
97
98#[path = "./unit_tests/utils.rs"]
99pub mod utils;
100
101macro_rules! built_in_ids {
102 ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
103 $(
104 pub const $addr: AccountAddress = builtin_address($init);
105 pub const $id: ObjectId = ObjectId::new($addr.into_bytes());
106 )*
107 }
108}
109
110macro_rules! built_in_pkgs {
111 ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
112 built_in_ids! { $($addr / $id = $init;)* }
113 }
114}
115
116built_in_pkgs! {
117 MOVE_STDLIB_ADDRESS / MOVE_STDLIB_PACKAGE_ID = 0x1;
118 IOTA_FRAMEWORK_ADDRESS / IOTA_FRAMEWORK_PACKAGE_ID = 0x2;
119 IOTA_SYSTEM_ADDRESS / IOTA_SYSTEM_PACKAGE_ID = 0x3;
120 GENESIS_BRIDGE_ADDRESS / GENESIS_BRIDGE_PACKAGE_ID = 0xb;
121 STARDUST_ADDRESS / STARDUST_PACKAGE_ID = 0x107a;
122}
123
124built_in_ids! {
125 IOTA_SYSTEM_STATE_ADDRESS / IOTA_SYSTEM_STATE_OBJECT_ID = 0x5;
126 IOTA_CLOCK_ADDRESS / IOTA_CLOCK_OBJECT_ID = 0x6;
127 IOTA_AUTHENTICATOR_STATE_ADDRESS / IOTA_AUTHENTICATOR_STATE_OBJECT_ID = 0x7;
128 IOTA_RANDOMNESS_STATE_ADDRESS / IOTA_RANDOMNESS_STATE_OBJECT_ID = 0x8;
129 GENESIS_IOTA_BRIDGE_ADDRESS / GENESIS_IOTA_BRIDGE_OBJECT_ID = 0x9;
130 IOTA_DENY_LIST_ADDRESS / IOTA_DENY_LIST_OBJECT_ID = 0x403;
131 IOTA_TRANSACTION_DENY_RULES_ADDRESS / IOTA_TRANSACTION_DENY_RULES_OBJECT_ID = 0xde9;
132}
133
134pub const SYSTEM_PACKAGE_ADDRESSES: [Address; 5] = [
135 Address::STD,
136 Address::FRAMEWORK,
137 Address::SYSTEM,
138 Address::GENESIS_BRIDGE,
139 Address::STARDUST,
140];
141
142pub const IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION: Version = OBJECT_START_VERSION;
143pub const IOTA_CLOCK_OBJECT_SHARED_VERSION: Version = OBJECT_START_VERSION;
144
145const fn builtin_address(suffix: u16) -> AccountAddress {
146 let mut addr = [0u8; AccountAddress::LENGTH];
147 let [hi, lo] = suffix.to_be_bytes();
148 addr[AccountAddress::LENGTH - 2] = hi;
149 addr[AccountAddress::LENGTH - 1] = lo;
150 AccountAddress::new(addr)
151}
152
153pub fn iota_framework_address_concat_string(suffix: &str) -> String {
154 format!("{}{suffix}", Address::FRAMEWORK.to_short_hex())
155}
156
157pub fn parse_iota_address(s: &str) -> anyhow::Result<Address> {
166 use move_core_types::parsing::address::ParsedAddress;
167 Ok(Address::new(
168 ParsedAddress::parse(s)?
169 .into_account_address(&resolve_address)?
170 .into_bytes(),
171 ))
172}
173
174pub fn parse_iota_module_id(s: &str) -> anyhow::Result<ModuleId> {
179 use move_core_types::parsing::types::ParsedModuleId;
180 ParsedModuleId::parse(s)?.into_module_id(&resolve_address)
181}
182
183pub fn parse_iota_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> {
189 use move_core_types::parsing::types::ParsedFqName;
190 ParsedFqName::parse(s)?.into_fq_name(&resolve_address)
191}
192
193pub fn parse_iota_struct_tag(s: &str) -> anyhow::Result<StructTag> {
199 use move_core_types::parsing::types::ParsedStructType;
200 ParsedStructType::parse(s)?
201 .into_struct_tag(&resolve_address)
202 .map(|s| struct_tag_core_to_sdk(&s))
203}
204
205pub fn parse_iota_type_tag(s: &str) -> anyhow::Result<TypeTag> {
210 use move_core_types::parsing::types::ParsedType;
211 ParsedType::parse(s)?
212 .into_type_tag(&resolve_address)
213 .map(|s| type_tag_core_to_sdk(&s))
214}
215
216pub fn resolve_address(addr: &str) -> Option<AccountAddress> {
218 match addr {
219 "std" => Some(Address::STD),
220 "iota" => Some(Address::FRAMEWORK),
221 "iota_system" => Some(Address::SYSTEM),
222 "stardust" => Some(Address::STARDUST),
223 _ => None,
224 }
225 .map(|addr| AccountAddress::new(addr.into_bytes()))
226}
227
228pub trait MoveTypeTagTrait {
229 fn get_type_tag() -> TypeTag;
230}
231
232impl MoveTypeTagTrait for u8 {
233 fn get_type_tag() -> TypeTag {
234 TypeTag::U8
235 }
236}
237
238impl MoveTypeTagTrait for u64 {
239 fn get_type_tag() -> TypeTag {
240 TypeTag::U64
241 }
242}
243
244impl MoveTypeTagTrait for String {
245 fn get_type_tag() -> TypeTag {
246 TypeTag::Struct(Box::new(StructTag::new_string()))
247 }
248}
249
250impl MoveTypeTagTrait for ObjectId {
251 fn get_type_tag() -> TypeTag {
252 TypeTag::Address
253 }
254}
255
256impl MoveTypeTagTrait for Address {
257 fn get_type_tag() -> TypeTag {
258 TypeTag::Address
259 }
260}
261
262impl MoveTypeTagTrait for iota_sdk_move_types::iota_framework::object::ID {
263 fn get_type_tag() -> TypeTag {
264 TypeTag::Struct(Box::new(StructTag::new_id()))
265 }
266}
267
268impl<N: MoveTypeTagTrait> MoveTypeTagTrait
269 for iota_sdk_move_types::iota_framework::dynamic_object_field::Wrapper<N>
270{
271 fn get_type_tag() -> TypeTag {
272 TypeTag::Struct(Box::new(
273 dynamic_field::DynamicFieldInfo::dynamic_object_field_wrapper(N::get_type_tag()),
274 ))
275 }
276}
277
278impl MoveTypeTagTrait for iota_sdk_move_types::iota_framework::deny_list::ConfigKey {
279 fn get_type_tag() -> TypeTag {
280 TypeTag::Struct(Box::new(StructTag::new_deny_list_config_key()))
281 }
282}
283
284impl MoveTypeTagTrait for iota_sdk_move_types::iota_framework::deny_list::AddressKey {
285 fn get_type_tag() -> TypeTag {
286 TypeTag::Struct(Box::new(StructTag::new_deny_list_address_key()))
287 }
288}
289
290impl MoveTypeTagTrait for iota_sdk_move_types::iota_framework::deny_list::GlobalPauseKey {
291 fn get_type_tag() -> TypeTag {
292 TypeTag::Struct(Box::new(StructTag::new_deny_list_global_pause_key()))
293 }
294}
295
296impl<T: MoveTypeTagTrait> MoveTypeTagTrait for Vec<T> {
297 fn get_type_tag() -> TypeTag {
298 TypeTag::Vector(Box::new(T::get_type_tag()))
299 }
300}
301
302pub fn is_primitive(
305 view: &CompiledModule,
306 function_type_args: &[AbilitySet],
307 s: &SignatureToken,
308) -> bool {
309 is_primitive_inner(view, function_type_args, s, false)
310}
311
312pub fn is_primitive_strict(
315 view: &CompiledModule,
316 function_type_args: &[AbilitySet],
317 s: &SignatureToken,
318) -> bool {
319 is_primitive_inner(view, function_type_args, s, true)
320}
321
322pub fn is_primitive_inner(
328 view: &CompiledModule,
329 function_type_args: &[AbilitySet],
330 s: &SignatureToken,
331 is_strict: bool,
332) -> bool {
333 use SignatureToken as S;
334 match s {
335 S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true,
336 S::Signer => false,
337 S::TypeParameter(idx) => {
340 if !is_strict {
341 !function_type_args[*idx as usize].has_key()
343 } else {
344 let abilities = function_type_args[*idx as usize];
347 !abilities.has_key() && (abilities.has_copy() || abilities.has_drop())
348 }
349 }
350
351 S::Datatype(idx) => [RESOLVED_IOTA_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR]
352 .contains(&resolve_struct(view, *idx)),
353
354 S::DatatypeInstantiation(inst) => {
355 let (idx, targs) = &**inst;
356 let resolved_struct = resolve_struct(view, *idx);
357 resolved_struct == RESOLVED_STD_OPTION
359 && targs.len() == 1
360 && is_primitive_inner(view, function_type_args, &targs[0], is_strict)
361 }
362
363 S::Vector(inner) => is_primitive_inner(view, function_type_args, inner, is_strict),
364 S::Reference(_) | S::MutableReference(_) => false,
365 }
366}
367
368pub fn is_object(
369 view: &CompiledModule,
370 function_type_args: &[AbilitySet],
371 t: &SignatureToken,
372) -> Result<bool, String> {
373 use SignatureToken as S;
374 match t {
375 S::Reference(inner) | S::MutableReference(inner) => {
376 is_object(view, function_type_args, inner)
377 }
378 _ => is_object_struct(view, function_type_args, t),
379 }
380}
381
382pub fn is_object_vector(
383 view: &CompiledModule,
384 function_type_args: &[AbilitySet],
385 t: &SignatureToken,
386) -> Result<bool, String> {
387 use SignatureToken as S;
388 match t {
389 S::Vector(inner) => is_object_struct(view, function_type_args, inner),
390 _ => is_object_struct(view, function_type_args, t),
391 }
392}
393
394pub fn is_object_struct(
395 view: &CompiledModule,
396 function_type_args: &[AbilitySet],
397 s: &SignatureToken,
398) -> Result<bool, String> {
399 use SignatureToken as S;
400 match s {
401 S::Bool
402 | S::U8
403 | S::U16
404 | S::U32
405 | S::U64
406 | S::U128
407 | S::U256
408 | S::Address
409 | S::Signer
410 | S::Vector(_)
411 | S::Reference(_)
412 | S::MutableReference(_) => Ok(false),
413 S::TypeParameter(idx) => Ok(function_type_args
414 .get(*idx as usize)
415 .map(|abs| abs.has_key())
416 .unwrap_or(false)),
417 S::Datatype(_) | S::DatatypeInstantiation(_) => {
418 let abilities = view
419 .abilities(s, function_type_args)
420 .map_err(|vm_err| vm_err.to_string())?;
421 Ok(abilities.has_key())
422 }
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use expect_test::expect;
429
430 use super::*;
431
432 #[test]
433 fn test_parse_iota_numeric_address() {
434 let result = parse_iota_address("0x2").expect("should not error");
435
436 let expected =
437 expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
438 expected.assert_eq(&result.to_string());
439 }
440
441 #[test]
442 fn test_parse_iota_named_address() {
443 let result = parse_iota_address("iota").expect("should not error");
444
445 let expected =
446 expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
447 expected.assert_eq(&result.to_string());
448 }
449
450 #[test]
451 fn test_parse_iota_module_id() {
452 let result = parse_iota_module_id("0x2::iota").expect("should not error");
453 let expected =
454 expect!["0x0000000000000000000000000000000000000000000000000000000000000002::iota"];
455 expected.assert_eq(&result.to_canonical_string(true));
456 }
457
458 #[test]
459 fn test_parse_iota_fq_name() {
460 let (module, name) = parse_iota_fq_name("0x2::object::new").expect("should not error");
461 let expected = expect![
462 "0x0000000000000000000000000000000000000000000000000000000000000002::object::new"
463 ];
464 expected.assert_eq(&format!(
465 "{}::{name}",
466 module.to_canonical_display(true)
467 ));
468 }
469
470 #[test]
471 fn test_parse_iota_struct_tag_short_account_addr() {
472 let result = parse_iota_struct_tag("0x2::iota::IOTA").expect("should not error");
473
474 let expected = expect!["0x2::iota::IOTA"];
475 expected.assert_eq(&result.to_string());
476
477 let expected = expect![
478 "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA"
479 ];
480 expected.assert_eq(&result.to_canonical_string(true));
481 }
482
483 #[test]
484 fn test_parse_iota_struct_tag_long_account_addr() {
485 let result = parse_iota_struct_tag(
486 "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA",
487 )
488 .expect("should not error");
489
490 let expected = expect!["0x2::iota::IOTA"];
491 expected.assert_eq(&result.to_string());
492
493 let expected = expect![
494 "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA"
495 ];
496 expected.assert_eq(&result.to_canonical_string(true));
497 }
498
499 #[test]
500 fn test_parse_iota_struct_with_type_param_short_addr() {
501 let result =
502 parse_iota_struct_tag("0x2::coin::COIN<0x2::iota::IOTA>").expect("should not error");
503
504 let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"];
505 expected.assert_eq(&result.to_string());
506
507 let expected = expect![
508 "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>"
509 ];
510 expected.assert_eq(&result.to_canonical_string(true));
511 }
512
513 #[test]
514 fn test_parse_iota_struct_with_type_param_long_addr() {
515 let result = parse_iota_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>")
516 .expect("should not error");
517
518 let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"];
519 expected.assert_eq(&result.to_string());
520
521 let expected = expect![
522 "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>"
523 ];
524 expected.assert_eq(&result.to_canonical_string(true));
525 }
526
527 #[test]
528 fn test_complex_struct_tag_with_short_addr() {
529 let result = parse_iota_struct_tag(
530 "0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>",
531 )
532 .expect("should not error");
533
534 let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>"];
535 expected.assert_eq(&result.to_string());
536
537 let expected = expect![
538 "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>"
539 ];
540 expected.assert_eq(&result.to_canonical_string(true));
541 }
542
543 #[test]
544 fn test_complex_struct_tag_with_long_addr() {
545 let result = parse_iota_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>")
546 .expect("should not error");
547
548 let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>"];
549 expected.assert_eq(&result.to_string());
550
551 let expected = expect![
552 "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>"
553 ];
554 expected.assert_eq(&result.to_canonical_string(true));
555 }
556
557 #[test]
558 fn test_dynamic_field_short_addr() {
559 let result = parse_iota_struct_tag(
560 "0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>",
561 )
562 .expect("should not error");
563
564 let expected =
565 expect!["0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>"];
566 expected.assert_eq(&result.to_string());
567
568 let expected = expect![
569 "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
570 ];
571 expected.assert_eq(&result.to_canonical_string(true));
572 }
573
574 #[test]
575 fn test_dynamic_field_long_addr() {
576 let result = parse_iota_struct_tag(
577 "0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>",
578 )
579 .expect("should not error");
580
581 let expected =
582 expect!["0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>"];
583 expected.assert_eq(&result.to_string());
584
585 let expected = expect![
586 "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
587 ];
588 expected.assert_eq(&result.to_canonical_string(true));
589 }
590}