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