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