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