sui_types/
lib.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3#![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 object;
81pub mod passkey_authenticator;
82pub mod programmable_transaction_builder;
83pub mod proto_value;
84pub mod ptb_trace;
85pub mod quorum_driver_types;
86pub mod randomness_state;
87pub mod rpc_proto_conversions;
88pub mod signature;
89pub mod signature_verification;
90pub mod storage;
91pub mod sui_sdk_types_conversions;
92pub mod sui_serde;
93pub mod sui_system_state;
94pub mod supported_protocol_versions;
95pub mod test_checkpoint_data_builder;
96pub mod traffic_control;
97pub mod transaction;
98pub mod transaction_executor;
99pub mod transfer;
100pub mod type_input;
101pub mod versioned;
102pub mod zk_login_authenticator;
103pub mod zk_login_util;
104
105#[path = "./unit_tests/utils.rs"]
106pub mod utils;
107
108macro_rules! built_in_ids {
109    ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
110        $(
111            pub const $addr: AccountAddress = AccountAddress::from_suffix($init);
112            pub const $id: ObjectID = ObjectID::from_address($addr);
113        )*
114    }
115}
116
117macro_rules! built_in_pkgs {
118    ($($addr:ident / $id:ident = $init:expr);* $(;)?) => {
119        built_in_ids! { $($addr / $id = $init;)* }
120        pub const SYSTEM_PACKAGE_ADDRESSES: &[AccountAddress] = &[$($addr),*];
121        pub fn is_system_package(addr: impl Into<AccountAddress>) -> bool {
122            matches!(addr.into(), $($addr)|*)
123        }
124    }
125}
126
127built_in_pkgs! {
128    MOVE_STDLIB_ADDRESS / MOVE_STDLIB_PACKAGE_ID = 0x1;
129    SUI_FRAMEWORK_ADDRESS / SUI_FRAMEWORK_PACKAGE_ID = 0x2;
130    SUI_SYSTEM_ADDRESS / SUI_SYSTEM_PACKAGE_ID = 0x3;
131    BRIDGE_ADDRESS / BRIDGE_PACKAGE_ID = 0xb;
132    DEEPBOOK_ADDRESS / DEEPBOOK_PACKAGE_ID = 0xdee9;
133}
134
135built_in_ids! {
136    SUI_SYSTEM_STATE_ADDRESS / SUI_SYSTEM_STATE_OBJECT_ID = 0x5;
137    SUI_CLOCK_ADDRESS / SUI_CLOCK_OBJECT_ID = 0x6;
138    SUI_AUTHENTICATOR_STATE_ADDRESS / SUI_AUTHENTICATOR_STATE_OBJECT_ID = 0x7;
139    SUI_RANDOMNESS_STATE_ADDRESS / SUI_RANDOMNESS_STATE_OBJECT_ID = 0x8;
140    SUI_BRIDGE_ADDRESS / SUI_BRIDGE_OBJECT_ID = 0x9;
141    SUI_COIN_REGISTRY_ADDRESS / SUI_COIN_REGISTRY_OBJECT_ID = 0xc;
142    SUI_DISPLAY_REGISTRY_ADDRESS / SUI_DISPLAY_REGISTRY_OBJECT_ID = 0xd;
143    SUI_DENY_LIST_ADDRESS / SUI_DENY_LIST_OBJECT_ID = 0x403;
144    SUI_ACCUMULATOR_ROOT_ADDRESS / SUI_ACCUMULATOR_ROOT_OBJECT_ID = 0xacc;
145    SUI_ADDRESS_ALIAS_STATE_ADDRESS / SUI_ADDRESS_ALIAS_STATE_OBJECT_ID = 0xa;
146}
147
148pub const SUI_SYSTEM_STATE_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
149pub const SUI_CLOCK_OBJECT_SHARED_VERSION: SequenceNumber = OBJECT_START_VERSION;
150
151pub fn sui_framework_address_concat_string(suffix: &str) -> String {
152    format!("{}{suffix}", SUI_FRAMEWORK_ADDRESS.to_hex_literal())
153}
154
155/// Parses `s` as an address. Valid formats for addresses are:
156///
157/// - A 256bit number, encoded in decimal, or hexadecimal with a leading "0x" prefix.
158/// - One of a number of pre-defined named addresses: std, sui, sui_system, deepbook.
159///
160/// Parsing succeeds if and only if `s` matches one of these formats exactly, with no remaining
161/// suffix. This function is intended for use within the authority codebases.
162pub fn parse_sui_address(s: &str) -> anyhow::Result<SuiAddress> {
163    use move_core_types::parsing::address::ParsedAddress;
164    Ok(ParsedAddress::parse(s)?
165        .into_account_address(&resolve_address)?
166        .into())
167}
168
169/// Parse `s` as a Module ID: An address (see `parse_sui_address`), followed by `::`, and then a
170/// module name (an identifier). Parsing succeeds if and only if `s` matches this format exactly,
171/// with no remaining input. This function is intended for use within the authority codebases.
172pub fn parse_sui_module_id(s: &str) -> anyhow::Result<ModuleId> {
173    use move_core_types::parsing::types::ParsedModuleId;
174    ParsedModuleId::parse(s)?.into_module_id(&resolve_address)
175}
176
177/// Parse `s` as a fully-qualified name: A Module ID (see `parse_sui_module_id`), followed by `::`,
178/// and then an identifier (for the module member). Parsing succeeds if and only if `s` matches this
179/// format exactly, with no remaining input. This function is intended for use within the authority
180/// codebases.
181pub fn parse_sui_fq_name(s: &str) -> anyhow::Result<(ModuleId, String)> {
182    use move_core_types::parsing::types::ParsedFqName;
183    ParsedFqName::parse(s)?.into_fq_name(&resolve_address)
184}
185
186/// Parse `s` as a struct type: A fully-qualified name, optionally followed by a list of type
187/// parameters (types -- see `parse_sui_type_tag`, separated by commas, surrounded by angle
188/// brackets). Parsing succeeds if and only if `s` matches this format exactly, with no remaining
189/// input. This function is intended for use within the authority codebase.
190pub fn parse_sui_struct_tag(s: &str) -> anyhow::Result<StructTag> {
191    use move_core_types::parsing::types::ParsedStructType;
192    ParsedStructType::parse(s)?.into_struct_tag(&resolve_address)
193}
194
195/// Parse `s` as a type: Either a struct type (see `parse_sui_struct_tag`), a primitive type, or a
196/// vector with a type parameter. Parsing succeeds if and only if `s` matches this format exactly,
197/// with no remaining input. This function is intended for use within the authority codebase.
198pub fn parse_sui_type_tag(s: &str) -> anyhow::Result<TypeTag> {
199    use move_core_types::parsing::types::ParsedType;
200    ParsedType::parse(s)?.into_type_tag(&resolve_address)
201}
202
203/// Resolve well-known named addresses into numeric addresses.
204pub fn resolve_address(addr: &str) -> Option<AccountAddress> {
205    match addr {
206        "deepbook" => Some(DEEPBOOK_ADDRESS),
207        "std" => Some(MOVE_STDLIB_ADDRESS),
208        "sui" => Some(SUI_FRAMEWORK_ADDRESS),
209        "sui_system" => Some(SUI_SYSTEM_ADDRESS),
210        "bridge" => Some(BRIDGE_ADDRESS),
211        _ => None,
212    }
213}
214
215pub trait MoveTypeTagTrait {
216    fn get_type_tag() -> TypeTag;
217
218    fn get_instance_type_tag(&self) -> TypeTag {
219        Self::get_type_tag()
220    }
221}
222
223impl MoveTypeTagTrait for u8 {
224    fn get_type_tag() -> TypeTag {
225        TypeTag::U8
226    }
227}
228
229impl MoveTypeTagTrait for u64 {
230    fn get_type_tag() -> TypeTag {
231        TypeTag::U64
232    }
233}
234
235impl MoveTypeTagTrait for ObjectID {
236    fn get_type_tag() -> TypeTag {
237        TypeTag::Address
238    }
239}
240
241impl MoveTypeTagTrait for SuiAddress {
242    fn get_type_tag() -> TypeTag {
243        TypeTag::Address
244    }
245}
246
247impl<T: MoveTypeTagTrait> MoveTypeTagTrait for Vec<T> {
248    fn get_type_tag() -> TypeTag {
249        TypeTag::Vector(Box::new(T::get_type_tag()))
250    }
251}
252
253pub trait MoveTypeTagTraitGeneric {
254    fn get_type_tag(type_params: &[TypeTag]) -> TypeTag;
255}
256
257pub fn is_primitive(
258    view: &CompiledModule,
259    function_type_args: &[AbilitySet],
260    s: &SignatureToken,
261) -> bool {
262    use SignatureToken as S;
263    match s {
264        S::Bool | S::U8 | S::U16 | S::U32 | S::U64 | S::U128 | S::U256 | S::Address => true,
265        S::Signer => false,
266        // optimistic, but no primitive has key
267        S::TypeParameter(idx) => !function_type_args[*idx as usize].has_key(),
268
269        S::Datatype(idx) => [RESOLVED_SUI_ID, RESOLVED_ASCII_STR, RESOLVED_UTF8_STR]
270            .contains(&resolve_struct(view, *idx)),
271
272        S::DatatypeInstantiation(inst) => {
273            let (idx, targs) = &**inst;
274            let resolved_struct = resolve_struct(view, *idx);
275            // option is a primitive
276            resolved_struct == RESOLVED_STD_OPTION
277                && targs.len() == 1
278                && is_primitive(view, function_type_args, &targs[0])
279        }
280
281        S::Vector(inner) => is_primitive(view, function_type_args, inner),
282        S::Reference(_) | S::MutableReference(_) => false,
283    }
284}
285
286pub fn is_object(
287    view: &CompiledModule,
288    function_type_args: &[AbilitySet],
289    t: &SignatureToken,
290) -> Result<bool, String> {
291    use SignatureToken as S;
292    match t {
293        S::Reference(inner) | S::MutableReference(inner) => {
294            is_object(view, function_type_args, inner)
295        }
296        _ => is_object_struct(view, function_type_args, t),
297    }
298}
299
300pub fn is_object_vector(
301    view: &CompiledModule,
302    function_type_args: &[AbilitySet],
303    t: &SignatureToken,
304) -> Result<bool, String> {
305    use SignatureToken as S;
306    match t {
307        S::Vector(inner) => is_object_struct(view, function_type_args, inner),
308        _ => is_object_struct(view, function_type_args, t),
309    }
310}
311
312fn is_object_struct(
313    view: &CompiledModule,
314    function_type_args: &[AbilitySet],
315    s: &SignatureToken,
316) -> Result<bool, String> {
317    use SignatureToken as S;
318    match s {
319        S::Bool
320        | S::U8
321        | S::U16
322        | S::U32
323        | S::U64
324        | S::U128
325        | S::U256
326        | S::Address
327        | S::Signer
328        | S::Vector(_)
329        | S::Reference(_)
330        | S::MutableReference(_) => Ok(false),
331        S::TypeParameter(idx) => Ok(function_type_args
332            .get(*idx as usize)
333            .map(|abs| abs.has_key())
334            .unwrap_or(false)),
335        S::Datatype(_) | S::DatatypeInstantiation(_) => {
336            let abilities = view
337                .abilities(s, function_type_args)
338                .map_err(|vm_err| vm_err.to_string())?;
339            Ok(abilities.has_key())
340        }
341    }
342}
343
344#[cfg(test)]
345mod tests {
346    use super::*;
347    use expect_test::expect;
348
349    #[test]
350    fn test_parse_sui_numeric_address() {
351        let result = parse_sui_address("0x2").expect("should not error");
352
353        let expected =
354            expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
355        expected.assert_eq(&result.to_string());
356    }
357
358    #[test]
359    fn test_parse_sui_named_address() {
360        let result = parse_sui_address("sui").expect("should not error");
361
362        let expected =
363            expect!["0x0000000000000000000000000000000000000000000000000000000000000002"];
364        expected.assert_eq(&result.to_string());
365    }
366
367    #[test]
368    fn test_parse_sui_module_id() {
369        let result = parse_sui_module_id("0x2::sui").expect("should not error");
370        let expected =
371            expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui"];
372        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
373    }
374
375    #[test]
376    fn test_parse_sui_fq_name() {
377        let (module, name) = parse_sui_fq_name("0x2::object::new").expect("should not error");
378        let expected = expect![
379            "0x0000000000000000000000000000000000000000000000000000000000000002::object::new"
380        ];
381        expected.assert_eq(&format!(
382            "{}::{name}",
383            module.to_canonical_display(/* with_prefix */ true)
384        ));
385    }
386
387    #[test]
388    fn test_parse_sui_struct_tag_short_account_addr() {
389        let result = parse_sui_struct_tag("0x2::sui::SUI").expect("should not error");
390
391        let expected = expect!["0x2::sui::SUI"];
392        expected.assert_eq(&result.to_string());
393
394        let expected =
395            expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"];
396        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
397    }
398
399    #[test]
400    fn test_parse_sui_struct_tag_long_account_addr() {
401        let result = parse_sui_struct_tag(
402            "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI",
403        )
404        .expect("should not error");
405
406        let expected = expect!["0x2::sui::SUI"];
407        expected.assert_eq(&result.to_string());
408
409        let expected =
410            expect!["0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"];
411        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
412    }
413
414    #[test]
415    fn test_parse_sui_struct_with_type_param_short_addr() {
416        let result =
417            parse_sui_struct_tag("0x2::coin::COIN<0x2::sui::SUI>").expect("should not error");
418
419        let expected = expect!["0x2::coin::COIN<0x2::sui::SUI>"];
420        expected.assert_eq(&result.to_string());
421
422        let expected = expect![
423            "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>"
424        ];
425        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
426    }
427
428    #[test]
429    fn test_parse_sui_struct_with_type_param_long_addr() {
430        let result = parse_sui_struct_tag("0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>")
431            .expect("should not error");
432
433        let expected = expect!["0x2::coin::COIN<0x2::sui::SUI>"];
434        expected.assert_eq(&result.to_string());
435
436        let expected = expect![
437            "0x0000000000000000000000000000000000000000000000000000000000000002::coin::COIN<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>"
438        ];
439        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
440    }
441
442    #[test]
443    fn test_complex_struct_tag_with_short_addr() {
444        let result =
445            parse_sui_struct_tag("0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::sui::SUI>>>")
446                .expect("should not error");
447
448        let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::sui::SUI>>>"];
449        expected.assert_eq(&result.to_string());
450
451        let expected = expect![
452            "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>>"
453        ];
454        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
455    }
456
457    #[test]
458    fn test_complex_struct_tag_with_long_addr() {
459        let result = parse_sui_struct_tag("0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>>")
460            .expect("should not error");
461
462        let expected = expect!["0xe7::vec_coin::VecCoin<vector<0x2::coin::Coin<0x2::sui::SUI>>>"];
463        expected.assert_eq(&result.to_string());
464
465        let expected = expect![
466            "0x00000000000000000000000000000000000000000000000000000000000000e7::vec_coin::VecCoin<vector<0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI>>>"
467        ];
468        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
469    }
470
471    #[test]
472    fn test_dynamic_field_short_addr() {
473        let result = parse_sui_struct_tag(
474            "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>",
475        )
476        .expect("should not error");
477
478        let expected = expect![
479            "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>"
480        ];
481        expected.assert_eq(&result.to_string());
482
483        let expected = expect![
484            "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x000000000000000000000000000000000000000000000000000000000000dee9::custodian_v2::Account<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
485        ];
486        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
487    }
488
489    #[test]
490    fn test_dynamic_field_long_addr() {
491        let result = parse_sui_struct_tag(
492            "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>",
493        )
494        .expect("should not error");
495
496        let expected = expect![
497            "0x2::dynamic_field::Field<address, 0xdee9::custodian_v2::Account<0x234::coin::COIN>>"
498        ];
499        expected.assert_eq(&result.to_string());
500
501        let expected = expect![
502            "0x0000000000000000000000000000000000000000000000000000000000000002::dynamic_field::Field<address,0x000000000000000000000000000000000000000000000000000000000000dee9::custodian_v2::Account<0x0000000000000000000000000000000000000000000000000000000000000234::coin::COIN>>"
503        ];
504        expected.assert_eq(&result.to_canonical_string(/* with_prefix */ true));
505    }
506}