Skip to main content

iota_sdk_types/
object_id.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use super::{Address, address::AddressParseError};
6
7/// An `ObjectId` is a 32-byte identifier used to uniquely identify an object on
8/// the IOTA blockchain.
9///
10/// ## Relationship to Address
11///
12/// [`Address`]es and `ObjectId`s share the same 32-byte addressable space but
13/// are derived leveraging different domain-separator values to ensure,
14/// cryptographically, that there won't be any overlap, e.g. there can't be a
15/// valid `Object` whose `ObjectId` is equal to that of the `Address` of a user
16/// account.
17///
18/// # BCS
19///
20/// An `ObjectId`'s BCS serialized form is defined by the following:
21///
22/// ```text
23/// object-id = address
24/// ```
25#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
26#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
27#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
28#[cfg_attr(feature = "bcs-schema", derive(iota_bcs_schema::BcsSchema))]
29pub struct ObjectId(pub(crate) Address);
30
31impl ObjectId {
32    pub const LENGTH: usize = Address::LENGTH;
33    pub const ZERO: Self = Self(Address::ZERO);
34    pub const MAX: Self = Self(Address::MAX);
35    pub const STD: Self = Self(Address::STD);
36    pub const FRAMEWORK: Self = Self(Address::FRAMEWORK);
37    pub const SYSTEM: Self = Self(Address::SYSTEM);
38    pub const GENESIS_BRIDGE: Self = Self(Address::GENESIS_BRIDGE);
39    pub const STARDUST: Self = Self(Address::STARDUST);
40    pub const SYSTEM_STATE: Self = Self(Address::SYSTEM_STATE);
41    pub const CLOCK: Self = Self(Address::CLOCK);
42    pub const AUTHENTICATOR_STATE: Self = Self(Address::AUTHENTICATOR_STATE);
43    pub const RANDOMNESS_STATE: Self = Self(Address::RANDOMNESS_STATE);
44    pub const GENESIS_IOTA_BRIDGE: Self = Self(Address::GENESIS_IOTA_BRIDGE);
45    pub const DENY_LIST: Self = Self(Address::DENY_LIST);
46    pub const TRANSACTION_DENY_RULES: Self = Self(Address::TRANSACTION_DENY_RULES);
47
48    /// Generates a new ObjectId from the provided byte array.
49    pub const fn new(bytes: [u8; Self::LENGTH]) -> Self {
50        Self(Address::new(bytes))
51    }
52
53    /// Creates an `ObjectId` from a `u16` suffix by setting the last two bytes.
54    pub const fn from_u16(suffix: u16) -> Self {
55        Self(Address::from_u16(suffix))
56    }
57
58    /// Checks if the object id is one of the system package ids.
59    /// The system packages are:
60    /// - STD
61    /// - FRAMEWORK
62    /// - SYSTEM
63    /// - GENESIS_BRIDGE
64    /// - STARDUST
65    pub fn is_system_package(&self) -> bool {
66        self.0.is_system_package()
67    }
68
69    /// Returns the string representation of this object id in hex format with
70    /// `0x` prefix.
71    pub fn to_hex(&self) -> String {
72        self.0.to_hex()
73    }
74
75    /// Returns the string representation of this object id in hex format
76    /// without `0x` prefix.
77    pub fn to_raw_hex(&self) -> String {
78        self.0.to_raw_hex()
79    }
80
81    /// Returns the shortest possible string representation of the object ID
82    /// (i.e. with leading zeroes trimmed).
83    pub fn to_short_hex(&self) -> String {
84        self.0.to_short_hex()
85    }
86
87    /// Returns the shortest possible string representation of the object id
88    /// (i.e. with leading zeroes trimmed), without `0x` prefix.
89    pub fn to_raw_short_hex(&self) -> String {
90        self.0.to_raw_short_hex()
91    }
92
93    /// Parses an ObjectId from a full-length hex string (64 hex characters),
94    /// with or without a `0x` prefix. Will return an error if the string is not
95    /// exactly 64 hex characters long (excluding the `0x` prefix).
96    pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
97        Address::from_hex(hex).map(Self)
98    }
99
100    /// Parses an ObjectId from a full-length hex string (64 hex characters),
101    /// with a mandatory `0x` prefix. Will return an error if the string is not
102    /// exactly 64 hex characters long (excluding the `0x` prefix).
103    pub fn from_prefixed_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
104        Address::from_prefixed_hex(hex).map(Self)
105    }
106
107    /// Parses an ObjectId from a full-length hex string (64 hex characters),
108    /// without a `0x` prefix. Will return an error if the string has a `0x`
109    /// prefix or is not exactly 64 hex characters long.
110    pub fn from_raw_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
111        Address::from_raw_hex(hex).map(Self)
112    }
113
114    /// Parses an ObjectId from a hex string, with or without a `0x` prefix.
115    /// The string can be of variable length; if it's shorter than 64 hex
116    /// characters, it will be left-padded with `0`s.
117    pub fn from_short_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
118        Address::from_short_hex(hex).map(Self)
119    }
120
121    /// Parses an ObjectId from a hex string with a mandatory `0x` prefix.
122    /// The string can be of variable length; if it's shorter than 64 hex
123    /// characters, it will be left-padded with `0`s.
124    pub fn from_prefixed_short_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
125        Address::from_prefixed_short_hex(hex).map(Self)
126    }
127
128    /// Parses an ObjectId from a hex string without a `0x` prefix.
129    /// The string can be of variable length; if it's shorter than 64 hex
130    /// characters, it will be left-padded with `0`s. Will return an error if
131    /// the string has a `0x` prefix.
132    pub fn from_raw_short_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
133        Address::from_raw_short_hex(hex).map(Self)
134    }
135
136    pub const fn from_address(address: Address) -> Self {
137        Self(address)
138    }
139
140    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, AddressParseError> {
141        Address::from_bytes(bytes).map(Self)
142    }
143
144    /// Returns the underlying byte array of an ObjectId.
145    pub const fn into_bytes(self) -> [u8; Self::LENGTH] {
146        self.0.into_bytes()
147    }
148
149    /// Returns a reference to the underlying byte array of an ObjectId.
150    pub const fn bytes(&self) -> &[u8; Self::LENGTH] {
151        self.0.bytes()
152    }
153
154    /// Returns a slice of bytes of an ObjectId.
155    pub const fn as_bytes(&self) -> &[u8] {
156        self.0.as_bytes()
157    }
158
159    /// Returns the underlying Address of an ObjectId.
160    pub const fn as_address(&self) -> &Address {
161        &self.0
162    }
163
164    /// Returns the string representation of this object ID using the
165    /// canonical display, with or without a `0x` prefix.
166    pub fn to_canonical_string(&self, with_prefix: bool) -> String {
167        self.0.to_canonical_string(with_prefix)
168    }
169
170    /// Returns the next object id in byte-increasing order.
171    pub const fn next_lexicographical(&self) -> Self {
172        Self::new(crate::next_lexicographical_array(self.bytes()))
173    }
174
175    /// Returns the next object id in byte-increasing order, or `None` if the
176    /// result would overflow.
177    pub const fn next_lexicographical_opt(&self) -> Option<Self> {
178        match crate::next_lexicographical_array_opt(self.bytes()) {
179            Some(val) => Some(Self::new(val)),
180            None => None,
181        }
182    }
183
184    #[cfg(feature = "rand")]
185    #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
186    pub fn random_with<R>(rng: R) -> Self
187    where
188        R: rand_core::RngCore + rand_core::CryptoRng,
189    {
190        Self::from_address(Address::random_with(rng))
191    }
192
193    #[cfg(feature = "rand")]
194    #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
195    pub fn random() -> Self {
196        Self::random_with(rand_core::OsRng)
197    }
198}
199
200impl AsRef<[u8]> for ObjectId {
201    fn as_ref(&self) -> &[u8] {
202        self.0.as_ref()
203    }
204}
205
206impl AsRef<[u8; 32]> for ObjectId {
207    fn as_ref(&self) -> &[u8; 32] {
208        self.0.as_ref()
209    }
210}
211
212impl From<ObjectId> for [u8; 32] {
213    fn from(object_id: ObjectId) -> Self {
214        object_id.into_bytes()
215    }
216}
217
218impl From<[u8; 32]> for ObjectId {
219    fn from(object_id: [u8; 32]) -> Self {
220        Self::new(object_id)
221    }
222}
223
224impl From<Address> for ObjectId {
225    fn from(value: Address) -> Self {
226        Self(value)
227    }
228}
229
230impl From<ObjectId> for Vec<u8> {
231    fn from(value: ObjectId) -> Self {
232        value.0.into()
233    }
234}
235
236impl std::str::FromStr for ObjectId {
237    type Err = AddressParseError;
238
239    fn from_str(s: &str) -> Result<Self, Self::Err> {
240        Address::from_str(s).map(Self)
241    }
242}
243
244impl std::fmt::Debug for ObjectId {
245    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246        write!(f, "ObjectId(\"{self}\")")
247    }
248}
249
250impl std::fmt::Display for ObjectId {
251    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252        self.to_canonical_string(true).fmt(f)
253    }
254}