Skip to main content

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