iota_types/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5#![warn(
6    future_incompatible,
7    nonstandard_style,
8    rust_2018_idioms,
9    rust_2021_compatibility
10)]
11
12use base_types::{IotaAddress, ObjectID, SequenceNumber, StructTag, TypeTag};
13pub use iota_network_stack::multiaddr;
14pub use iota_sdk_types as sdk_types;
15use move_binary_format::{
16    CompiledModule,
17    file_format::{AbilitySet, SignatureToken},
18};
19use move_bytecode_utils::resolve_struct;
20use move_core_types::{account_address::AccountAddress, language_storage::ModuleId};
21use object::OBJECT_START_VERSION;
22
23use crate::{
24    base_types::{RESOLVED_ASCII_STR, RESOLVED_STD_OPTION, RESOLVED_UTF8_STR},
25    id::RESOLVED_IOTA_ID,
26    iota_sdk_types_conversions::{struct_tag_core_to_sdk, type_tag_core_to_sdk},
27};
28
29#[macro_use]
30pub mod error;
31
32pub mod account_abstraction;
33pub mod auth_context;
34pub mod balance;
35pub mod base_types;
36pub mod clock;
37pub mod coin;
38pub mod coin_manager;
39pub mod collection_types;
40pub mod committee;
41pub mod config;
42pub mod crypto;
43pub mod deny_list_v1;
44pub mod derived_object;
45pub mod digests;
46pub mod display;
47pub mod dynamic_field;
48pub mod effects;
49pub mod epoch_data;
50pub mod event;
51pub mod executable_transaction;
52pub mod execution;
53pub mod execution_config_utils;
54pub mod execution_status;
55pub mod full_checkpoint_content;
56pub mod gas;
57pub mod gas_coin;
58pub mod gas_model;
59pub mod global_state_hash;
60pub mod governance;
61pub mod id;
62pub mod in_memory_storage;
63pub mod inner_temporary_store;
64pub mod iota_sdk_types_conversions;
65pub mod iota_serde;
66pub mod iota_system_state;
67pub mod layout_resolver;
68pub mod message_envelope;
69pub mod messages_checkpoint;
70pub mod messages_consensus;
71pub mod messages_grpc;
72pub mod messages_safe_client;
73pub mod metrics;
74pub mod mock_checkpoint_builder;
75pub mod move_authenticator;
76pub mod move_package;
77pub mod multisig;
78pub mod object;
79pub mod passkey_authenticator;
80pub mod programmable_transaction_builder;
81pub mod proto_value;
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 system_admin_cap;
90pub mod test_checkpoint_data_builder;
91pub mod timelock;
92pub mod traffic_control;
93pub mod transaction;
94pub mod transaction_executor;
95pub mod transfer;
96pub mod versioned;
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}
132
133pub const SYSTEM_PACKAGE_ADDRESSES: [IotaAddress; 5] = [
134    IotaAddress::STD,
135    IotaAddress::FRAMEWORK,
136    IotaAddress::SYSTEM,
137    IotaAddress::GENESIS_BRIDGE,
138    IotaAddress::STARDUST,
139];
140
141pub const IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
142pub const IOTA_CLOCK_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
143
144const fn builtin_address(suffix: u16) -> AccountAddress {
145    let mut addr = [0u8; AccountAddress::LENGTH];
146    let [hi, lo] = suffix.to_be_bytes();
147    addr[AccountAddress::LENGTH - 2] = hi;
148    addr[AccountAddress::LENGTH - 1] = lo;
149    AccountAddress::new(addr)
150}
151
152pub fn iota_framework_address_concat_string(suffix: &str) -> String {
153    format!("{}{suffix}", IotaAddress::FRAMEWORK.to_short_hex())
154}
155
156/// Parses `s` as an address. Valid formats for addresses are:
157///
158/// - A 256bit number, encoded in decimal, or hexadecimal with a leading "0x"
159///   prefix.
160/// - One of a number of pre-defined named addresses: std, iota, iota_system,
161///   stardust.
162///
163/// Parsing succeeds if and only if `s` matches one of these formats exactly,
164/// with no remaining suffix. This function is intended for use within the
165/// authority codebases.
166pub fn parse_iota_address(s: &str) -> anyhow::Result<IotaAddress> {
167    use move_core_types::parsing::address::ParsedAddress;
168    Ok(IotaAddress::new(
169        ParsedAddress::parse(s)?
170            .into_account_address(&resolve_address)?
171            .into_bytes(),
172    ))
173}
174
175/// Parse `s` as a Module ID: An address (see `parse_iota_address`), followed by
176/// `::`, and then a module name (an identifier). Parsing succeeds if and only
177/// if `s` matches this format exactly, with no remaining input. This function
178/// is intended for use within the authority codebases.
179pub fn parse_iota_module_id(s: &str) -> anyhow::Result<ModuleId> {
180    use move_core_types::parsing::types::ParsedModuleId;
181    ParsedModuleId::parse(s)?.into_module_id(&resolve_address)
182}
183
184/// Parse `s` as a fully-qualified name: A Module ID (see
185/// `parse_iota_module_id`), followed by `::`, and then an identifier (for the
186/// module member). Parsing succeeds if and only if `s` matches this
187/// format exactly, with no remaining input. This function is intended for use
188/// within the authority codebases.
189pub fn parse_iota_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> {
190    use move_core_types::parsing::types::ParsedFqName;
191    ParsedFqName::parse(s)?.into_fq_name(&resolve_address)
192}
193
194/// Parse `s` as a struct type: A fully-qualified name, optionally followed by a
195/// list of type parameters (types -- see `parse_iota_type_tag`, separated by
196/// commas, surrounded by angle brackets). Parsing succeeds if and only if `s`
197/// matches this format exactly, with no remaining input. This function is
198/// intended for use within the authority codebase.
199pub fn parse_iota_struct_tag(s: &str) -> anyhow::Result<StructTag> {
200    use move_core_types::parsing::types::ParsedStructType;
201    ParsedStructType::parse(s)?
202        .into_struct_tag(&resolve_address)
203        .map(|s| struct_tag_core_to_sdk(&s))
204}
205
206/// Parse `s` as a type: Either a struct type (see `parse_iota_struct_tag`), a
207/// primitive type, or a vector with a type parameter. Parsing succeeds if and
208/// only if `s` matches this format exactly, with no remaining input. This
209/// function is intended for use within the authority codebase.
210pub fn parse_iota_type_tag(s: &str) -> anyhow::Result<TypeTag> {
211    use move_core_types::parsing::types::ParsedType;
212    ParsedType::parse(s)?
213        .into_type_tag(&resolve_address)
214        .map(|s| type_tag_core_to_sdk(&s))
215}
216
217/// Resolve well-known named addresses into numeric addresses.
218pub fn resolve_address(addr: &str) -> Option<AccountAddress> {
219    match addr {
220        "std" => Some(IotaAddress::STD),
221        "iota" => Some(IotaAddress::FRAMEWORK),
222        "iota_system" => Some(IotaAddress::SYSTEM),
223        "stardust" => Some(IotaAddress::STARDUST),
224        _ => None,
225    }
226    .map(|addr| AccountAddress::new(addr.into_bytes()))
227}
228
229pub trait MoveTypeTagTrait {
230    fn get_type_tag() -> TypeTag;
231}
232
233impl MoveTypeTagTrait for u8 {
234    fn get_type_tag() -> TypeTag {
235        TypeTag::U8
236    }
237}
238
239impl MoveTypeTagTrait for u64 {
240    fn get_type_tag() -> TypeTag {
241        TypeTag::U64
242    }
243}
244
245impl MoveTypeTagTrait for ObjectID {
246    fn get_type_tag() -> TypeTag {
247        TypeTag::Address
248    }
249}
250
251impl MoveTypeTagTrait for IotaAddress {
252    fn get_type_tag() -> TypeTag {
253        TypeTag::Address
254    }
255}
256
257impl<T: MoveTypeTagTrait> MoveTypeTagTrait for Vec<T> {
258    fn get_type_tag() -> TypeTag {
259        TypeTag::Vector(Box::new(T::get_type_tag()))
260    }
261}
262
263/// Check if a type is a primitive type in optimistic mode. It invokes the inner
264/// function with is_strict = false.
265pub fn is_primitive(
266    view: &CompiledModule,
267    function_type_args: &[AbilitySet],
268    s: &SignatureToken,
269) -> bool {
270    is_primitive_inner(view, function_type_args, s, false)
271}
272
273/// Check if a type is a primitive type in strict mode. It invokes the inner
274/// function with is_strict = true.
275pub fn is_primitive_strict(
276    view: &CompiledModule,
277    function_type_args: &[AbilitySet],
278    s: &SignatureToken,
279) -> bool {
280    is_primitive_inner(view, function_type_args, s, true)
281}
282
283/// Check if a type is a primitive type.
284/// In optimistic mode (is_strict = false), a type parameter is considered
285/// primitive if it has no key ability. In strict mode (is_strict = true), a
286/// type parameter is considered primitive if it has at least copy or drop
287/// ability.
288pub fn is_primitive_inner(
289    view: &CompiledModule,
290    function_type_args: &[AbilitySet],
291    s: &SignatureToken,
292    is_strict: bool,
293) -> bool {
294    use SignatureToken as S;
295    match s {
296        S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true,
297        S::Signer => false,
298        // optimistic -> no primitive has key
299        // strict -> all primitives have at least copy or drop
300        S::TypeParameter(idx) => {
301            if !is_strict {
302                // optimistic: has no key
303                !function_type_args[*idx as usize].has_key()
304            } else {
305                // strict: has at least one of: copy or drop (or store and one of the others).
306                // copy or drop abilities always imply having no key, but here we double check
307                let abilities = function_type_args[*idx as usize];
308                !abilities.has_key() && (abilities.has_copy() || abilities.has_drop())
309            }
310        }
311
312        S::Datatype(idx) => [RESOLVED_IOTA_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR]
313            .contains(&resolve_struct(view, *idx)),
314
315        S::DatatypeInstantiation(inst) => {
316            let (idx, targs) = &**inst;
317            let resolved_struct = resolve_struct(view, *idx);
318            // option is a primitive
319            resolved_struct == RESOLVED_STD_OPTION
320                && targs.len() == 1
321                && is_primitive_inner(view, function_type_args, &targs[0], is_strict)
322        }
323
324        S::Vector(inner) => is_primitive_inner(view, function_type_args, inner, is_strict),
325        S::Reference(_) | S::MutableReference(_) => false,
326    }
327}
328
329pub fn is_object(
330    view: &CompiledModule,
331    function_type_args: &[AbilitySet],
332    t: &SignatureToken,
333) -> Result<bool, String> {
334    use SignatureToken as S;
335    match t {
336        S::Reference(inner) | S::MutableReference(inner) => {
337            is_object(view, function_type_args, inner)
338        }
339        _ => is_object_struct(view, function_type_args, t),
340    }
341}
342
343pub fn is_object_vector(
344    view: &CompiledModule,
345    function_type_args: &[AbilitySet],
346    t: &SignatureToken,
347) -> Result<bool, String> {
348    use SignatureToken as S;
349    match t {
350        S::Vector(inner) => is_object_struct(view, function_type_args, inner),
351        _ => is_object_struct(view, function_type_args, t),
352    }
353}
354
355pub fn is_object_struct(
356    view: &CompiledModule,
357    function_type_args: &[AbilitySet],
358    s: &SignatureToken,
359) -> Result<bool, String> {
360    use SignatureToken as S;
361    match s {
362        S::Bool
363        | S::U8
364        | S::U16
365        | S::U32
366        | S::U64
367        | S::U128
368        | S::U256
369        | S::Address
370        | S::Signer
371        | S::Vector(_)
372        | S::Reference(_)
373        | S::MutableReference(_) => Ok(false),
374        S::TypeParameter(idx) => Ok(function_type_args
375            .get(*idx as usize)
376            .map(|abs| abs.has_key())
377            .unwrap_or(false)),
378        S::Datatype(_) | S::DatatypeInstantiation(_) => {
379            let abilities = view
380                .abilities(s, function_type_args)
381                .map_err(|vm_err| vm_err.to_string())?;
382            Ok(abilities.has_key())
383        }
384    }
385}
386
387#[cfg(test)]
388mod tests {
389    use expect_test::expect;
390
391    use super::*;
392
393    #[test]
394    fn test_parse_iota_numeric_address() {
395        let result = parse_iota_address("0x2").expect("should not error");
396
397        let expected =
398            expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
399        expected.assert_eq(&result.to_string());
400    }
401
402    #[test]
403    fn test_parse_iota_named_address() {
404        let result = parse_iota_address("iota").expect("should not error");
405
406        let expected =
407            expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
408        expected.assert_eq(&result.to_string());
409    }
410
411    #[test]
412    fn test_parse_iota_module_id() {
413        let result = parse_iota_module_id("0x2::iota").expect("should not error");
414        let expected =
415            expect!["0x0000000000000000000000000000000000000000000000000000000000000002::iota"];
416        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
417    }
418
419    #[test]
420    fn test_parse_iota_fq_name() {
421        let (module, name) = parse_iota_fq_name("0x2::object::new").expect("should not error");
422        let expected = expect![
423            "0x0000000000000000000000000000000000000000000000000000000000000002::object::new"
424        ];
425        expected.assert_eq(&format!(
426            "{}::{name}",
427            module.to_canonical_display(/* with_prefix */ true)
428        ));
429    }
430
431    #[test]
432    fn test_parse_iota_struct_tag_short_account_addr() {
433        let result = parse_iota_struct_tag("0x2::iota::IOTA").expect("should not error");
434
435        let expected = expect!["0x2::iota::IOTA"];
436        expected.assert_eq(&result.to_string());
437
438        let expected = expect![
439            "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA"
440        ];
441        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
442    }
443
444    #[test]
445    fn test_parse_iota_struct_tag_long_account_addr() {
446        let result = parse_iota_struct_tag(
447            "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA",
448        )
449        .expect("should not error");
450
451        let expected = expect!["0x2::iota::IOTA"];
452        expected.assert_eq(&result.to_string());
453
454        let expected = expect![
455            "0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA"
456        ];
457        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
458    }
459
460    #[test]
461    fn test_parse_iota_struct_with_type_param_short_addr() {
462        let result =
463            parse_iota_struct_tag("0x2::coin::COIN<0x2::iota::IOTA>").expect("should not error");
464
465        let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"];
466        expected.assert_eq(&result.to_string());
467
468        let expected = expect![
469            "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>"
470        ];
471        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
472    }
473
474    #[test]
475    fn test_parse_iota_struct_with_type_param_long_addr() {
476        let result = parse_iota_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>")
477            .expect("should not error");
478
479        let expected = expect!["0x2::coin::COIN<0x2::iota::IOTA>"];
480        expected.assert_eq(&result.to_string());
481
482        let expected = expect![
483            "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>"
484        ];
485        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
486    }
487
488    #[test]
489    fn test_complex_struct_tag_with_short_addr() {
490        let result = parse_iota_struct_tag(
491            "0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>",
492        )
493        .expect("should not error");
494
495        let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>"];
496        expected.assert_eq(&result.to_string());
497
498        let expected = expect![
499            "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>"
500        ];
501        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
502    }
503
504    #[test]
505    fn test_complex_struct_tag_with_long_addr() {
506        let result = parse_iota_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>")
507            .expect("should not error");
508
509        let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::iota::IOTA>>>"];
510        expected.assert_eq(&result.to_string());
511
512        let expected = expect![
513            "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::iota::IOTA>>>"
514        ];
515        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
516    }
517
518    #[test]
519    fn test_dynamic_field_short_addr() {
520        let result = parse_iota_struct_tag(
521            "0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>",
522        )
523        .expect("should not error");
524
525        let expected =
526            expect!["0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>"];
527        expected.assert_eq(&result.to_string());
528
529        let expected = expect![
530            "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
531        ];
532        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
533    }
534
535    #[test]
536    fn test_dynamic_field_long_addr() {
537        let result = parse_iota_struct_tag(
538            "0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>",
539        )
540        .expect("should not error");
541
542        let expected =
543            expect!["0x2::dynamic_field::Field<address, 0x2::balance::Balance<0x234::coin::COIN>>"];
544        expected.assert_eq(&result.to_string());
545
546        let expected = expect![
547            "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x0000000000000000000000000000000000000000000000000000000000000002::balance::Balance<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
548        ];
549        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
550    }
551}