1use crate::ObjectId;
6
7#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
61#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
62#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
63#[cfg_attr(
64 feature = "bcs-schema",
65 derive(iota_bcs_schema::BcsSchema),
66 bcs_schema(definition = "32OCTET")
67)]
68pub struct Address(
69 #[cfg_attr(
70 feature = "serde",
71 serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable<ReadableAddress>>")
72 )]
73 [u8; Self::LENGTH],
74);
75
76impl Address {
77 pub const LENGTH: usize = 32;
78 pub const ZERO: Self = Self([0u8; Self::LENGTH]);
79 pub const MAX: Self = Self([u8::MAX; Self::LENGTH]);
80 pub const STD: Self = Self::from_u16(1);
81 pub const FRAMEWORK: Self = Self::from_u16(2);
82 pub const SYSTEM: Self = Self::from_u16(3);
83 pub const GENESIS_BRIDGE: Self = Self::from_u16(0xb);
84 pub const STARDUST: Self = Self::from_u16(0x107a);
85 pub const SYSTEM_STATE: Self = Self::from_u16(5);
86 pub const CLOCK: Self = Self::from_u16(6);
87 pub const AUTHENTICATOR_STATE: Self = Self::from_u16(7);
88 pub const RANDOMNESS_STATE: Self = Self::from_u16(8);
89 pub const GENESIS_IOTA_BRIDGE: Self = Self::from_u16(9);
90 pub const DENY_LIST: Self = Self::from_u16(0x403);
91 pub const TRANSACTION_DENY_RULES: Self = Self::from_u16(0xde9);
92
93 pub const fn new(bytes: [u8; Self::LENGTH]) -> Self {
94 Self(bytes)
95 }
96
97 pub const fn from_u16(suffix: u16) -> Self {
99 let mut address = Self::ZERO;
100 let [hi, lo] = suffix.to_be_bytes();
101 address.0[Address::LENGTH - 2] = hi;
102 address.0[Address::LENGTH - 1] = lo;
103 address
104 }
105
106 pub fn is_system_package(&self) -> bool {
114 [
115 Self::STD,
116 Self::FRAMEWORK,
117 Self::SYSTEM,
118 Self::GENESIS_BRIDGE,
119 Self::STARDUST,
120 ]
121 .contains(self)
122 }
123
124 #[cfg(feature = "rand")]
125 #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
126 pub fn random_with<R>(mut rng: R) -> Self
127 where
128 R: rand_core::RngCore + rand_core::CryptoRng,
129 {
130 let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
131 rng.fill_bytes(&mut buf);
132 Self::new(buf)
133 }
134
135 #[cfg(feature = "rand")]
136 #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
137 pub fn random() -> Self {
138 Self::random_with(rand_core::OsRng)
139 }
140
141 pub const fn into_bytes(self) -> [u8; Self::LENGTH] {
143 self.0
144 }
145
146 pub const fn bytes(&self) -> &[u8; Self::LENGTH] {
147 &self.0
148 }
149
150 pub const fn as_bytes(&self) -> &[u8] {
151 &self.0
152 }
153
154 pub const fn from_object_id(object_id: ObjectId) -> Self {
155 object_id.0
156 }
157
158 pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
162 let hex = hex.as_ref();
163 let hex = if hex.starts_with(b"0x") {
164 &hex[2..]
165 } else {
166 hex
167 };
168 if hex.len() != Self::LENGTH * 2 {
169 return Err(AddressParseError::FromHex(
170 hex::FromHexError::InvalidStringLength,
171 ));
172 }
173 <[u8; Self::LENGTH] as hex::FromHex>::from_hex(hex)
174 .map(Self)
175 .map_err(AddressParseError::FromHex)
176 }
177
178 pub fn from_prefixed_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
182 if !hex.as_ref().starts_with(b"0x") {
183 return Err(AddressParseError::MissingPrefix);
184 }
185 Self::from_hex(hex)
186 }
187
188 pub fn from_raw_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
192 if hex.as_ref().starts_with(b"0x") {
193 return Err(AddressParseError::UnexpectedPrefix);
194 }
195 Self::from_hex(hex)
196 }
197
198 pub fn from_short_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
202 let hex = hex.as_ref();
203 let hex = if hex.starts_with(b"0x") {
204 &hex[2..]
205 } else {
206 hex
207 };
208
209 if hex.len() < Self::LENGTH * 2 {
211 let mut buf = [b'0'; Self::LENGTH * 2];
212 let pad_length = (Self::LENGTH * 2) - hex.len();
213
214 buf[pad_length..].copy_from_slice(hex);
215
216 <[u8; Self::LENGTH] as hex::FromHex>::from_hex(buf)
217 } else {
218 <[u8; Self::LENGTH] as hex::FromHex>::from_hex(hex)
219 }
220 .map(Self)
221 .map_err(AddressParseError::FromHex)
222 }
223
224 pub fn from_prefixed_short_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
228 if !hex.as_ref().starts_with(b"0x") {
229 return Err(AddressParseError::MissingPrefix);
230 }
231 Self::from_short_hex(hex)
232 }
233
234 pub fn from_raw_short_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
239 if hex.as_ref().starts_with(b"0x") {
240 return Err(AddressParseError::UnexpectedPrefix);
241 }
242 Self::from_short_hex(hex)
243 }
244
245 pub fn to_hex(&self) -> String {
248 self.to_canonical_string(true)
249 }
250
251 pub fn to_raw_hex(&self) -> String {
254 self.to_canonical_string(false)
255 }
256
257 pub fn to_short_hex(&self) -> String {
260 format!("0x{}", self.to_raw_short_hex())
261 }
262
263 pub fn to_raw_short_hex(&self) -> String {
266 let full_str = self.to_canonical_string(false);
267 let trimmed = full_str.trim_start_matches('0');
268 let hex_str = if trimmed.is_empty() { "0" } else { trimmed };
269 hex_str.to_owned()
270 }
271
272 pub fn to_canonical_string(&self, with_prefix: bool) -> String {
275 let hex_str = hex::encode(self.0);
276 if with_prefix {
277 format!("0x{hex_str}")
278 } else {
279 hex_str
280 }
281 }
282
283 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, AddressParseError> {
284 let bytes = bytes.as_ref();
285 <[u8; Self::LENGTH]>::try_from(bytes)
286 .map_err(|_| AddressParseError::InvalidByteLength {
287 actual: bytes.len(),
288 })
289 .map(Self)
290 }
291
292 pub const fn next_lexicographical(&self) -> Self {
294 Self::new(crate::next_lexicographical_array(self.bytes()))
295 }
296
297 pub const fn next_lexicographical_opt(&self) -> Option<Self> {
300 match crate::next_lexicographical_array_opt(self.bytes()) {
301 Some(val) => Some(Self::new(val)),
302 None => None,
303 }
304 }
305}
306
307impl std::str::FromStr for Address {
308 type Err = AddressParseError;
309
310 fn from_str(s: &str) -> Result<Self, Self::Err> {
311 if s.starts_with("0x") {
313 Self::from_prefixed_short_hex(s)
314 } else {
315 Self::from_hex(s)
316 }
317 }
318}
319
320impl AsRef<[u8]> for Address {
321 fn as_ref(&self) -> &[u8] {
322 &self.0
323 }
324}
325
326impl AsRef<[u8; 32]> for Address {
327 fn as_ref(&self) -> &[u8; 32] {
328 &self.0
329 }
330}
331
332impl From<Address> for [u8; 32] {
333 fn from(address: Address) -> Self {
334 address.into_bytes()
335 }
336}
337
338impl From<[u8; 32]> for Address {
339 fn from(address: [u8; 32]) -> Self {
340 Self::new(address)
341 }
342}
343
344impl From<Address> for Vec<u8> {
345 fn from(value: Address) -> Self {
346 value.0.to_vec()
347 }
348}
349
350impl From<super::ObjectId> for Address {
351 fn from(value: super::ObjectId) -> Self {
352 Self::from_object_id(value)
353 }
354}
355
356impl std::fmt::Display for Address {
357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358 self.to_canonical_string(true).fmt(f)
359 }
360}
361
362impl std::fmt::Debug for Address {
363 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364 f.debug_tuple("Address")
365 .field(&format_args!("\"{self}\""))
366 .finish()
367 }
368}
369
370#[cfg(feature = "serde")]
371#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
372struct ReadableAddress;
373
374#[cfg(feature = "serde")]
375#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
376impl serde_with::SerializeAs<[u8; Address::LENGTH]> for ReadableAddress {
377 fn serialize_as<S>(source: &[u8; Address::LENGTH], serializer: S) -> Result<S::Ok, S::Error>
378 where
379 S: serde::Serializer,
380 {
381 let address = Address::new(*source);
382 serde_with::DisplayFromStr::serialize_as(&address, serializer)
383 }
384}
385
386#[cfg(feature = "serde")]
387#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
388impl<'de> serde_with::DeserializeAs<'de, [u8; Address::LENGTH]> for ReadableAddress {
389 fn deserialize_as<D>(deserializer: D) -> Result<[u8; Address::LENGTH], D::Error>
390 where
391 D: serde::Deserializer<'de>,
392 {
393 let address: Address = serde_with::DisplayFromStr::deserialize_as(deserializer)?;
394 Ok(address.into_bytes())
395 }
396}
397
398#[derive(Clone, Debug, PartialEq, thiserror::Error)]
399#[non_exhaustive]
400pub enum AddressParseError {
401 #[error("address must be hex string of length {}", Address::LENGTH * 2)]
402 FromHex(#[from] hex::FromHexError),
403 #[error(
404 "invalid address byte length: expected {}, got {actual}",
405 Address::LENGTH
406 )]
407 InvalidByteLength { actual: usize },
408 #[error("address hex string missing `0x` prefix")]
409 MissingPrefix,
410 #[error("address hex string has unexpected `0x` prefix")]
411 UnexpectedPrefix,
412}
413
414#[cfg(test)]
415mod tests {
416 #[cfg(feature = "proptest")]
417 mod proptests {
418 use test_strategy::proptest;
419
420 use super::super::Address;
421
422 #[proptest]
423 fn roundtrip_display_fromstr(address: Address) {
424 assert_eq!(address, address.to_string().parse().unwrap());
425 }
426 }
427
428 #[cfg(target_arch = "wasm32")]
429 use wasm_bindgen_test::wasm_bindgen_test as test;
430
431 use super::{Address, AddressParseError};
432
433 #[test]
434 fn parse_address_with_0x_prefix() {
435 let hex = "0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331";
436 let address = Address::from_short_hex(hex).unwrap();
437 assert_eq!(address.to_string(), hex);
438 }
439
440 #[test]
441 fn parse_address_without_0x_prefix() {
442 let hex = "02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331";
443 let address = Address::from_short_hex(hex).unwrap();
444 assert_eq!(
445 address.to_string(),
446 "0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331"
447 );
448 }
449
450 #[test]
451 fn parse_short_address_single_digit() {
452 let address = Address::from_short_hex("0x1").unwrap();
453 assert_eq!(address, Address::STD);
454 assert_eq!(
455 address.to_string(),
456 "0x0000000000000000000000000000000000000000000000000000000000000001"
457 );
458 }
459
460 #[test]
461 fn parse_short_address_without_prefix() {
462 let address = Address::from_short_hex("3").unwrap();
463 assert_eq!(address, Address::SYSTEM);
464 }
465
466 #[test]
467 fn parse_zero_address() {
468 let address = Address::from_short_hex("0x0").unwrap();
469 assert_eq!(address, Address::ZERO);
470
471 let address = Address::from_short_hex("0").unwrap();
472 assert_eq!(address, Address::ZERO);
473
474 let address = Address::from_short_hex(
475 "0x0000000000000000000000000000000000000000000000000000000000000000",
476 )
477 .unwrap();
478 assert_eq!(address, Address::ZERO);
479 }
480
481 #[test]
482 fn parse_address_invalid_hex_char() {
483 let result = Address::from_short_hex("0xGGGG");
484 assert!(result.is_err());
485 assert!(matches!(
486 result,
487 Err(AddressParseError::FromHex(
488 hex::FromHexError::InvalidHexCharacter { .. }
489 ))
490 ));
491 }
492
493 #[test]
494 fn parse_address_too_long() {
495 let result = Address::from_short_hex(
497 "0x002a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331",
498 );
499 assert!(matches!(
500 result,
501 Err(AddressParseError::FromHex(hex::FromHexError::OddLength))
502 ));
503
504 let result = Address::from_short_hex(
506 "0x002a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f3316",
507 );
508 assert!(matches!(
509 result,
510 Err(AddressParseError::FromHex(
511 hex::FromHexError::InvalidStringLength
512 ))
513 ));
514 }
515
516 #[test]
517 fn parse_raw_hex() {
518 let hex = "02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331";
519 let address = Address::from_raw_hex(hex).unwrap();
520 assert_eq!(address.to_raw_hex(), hex);
521
522 let result = Address::from_raw_hex(format!("0x{hex}"));
523 assert!(matches!(result, Err(AddressParseError::UnexpectedPrefix)));
524 }
525
526 #[test]
527 fn parse_raw_short_hex() {
528 let address = Address::from_raw_short_hex("2").unwrap();
529 assert_eq!(address, Address::FRAMEWORK);
530
531 let result = Address::from_raw_short_hex("0x2");
532 assert!(matches!(result, Err(AddressParseError::UnexpectedPrefix)));
533 }
534
535 #[test]
536 fn from_bytes_valid() {
537 let bytes = [0u8; 32];
538 let address = Address::from_bytes(bytes).unwrap();
539 assert_eq!(address, Address::ZERO);
540 }
541
542 #[test]
543 fn from_bytes_invalid_length() {
544 let bytes = [0u8; 31];
545 let result = Address::from_bytes(bytes);
546 assert!(matches!(
547 result,
548 Err(AddressParseError::InvalidByteLength { actual: 31 })
549 ));
550
551 let bytes = [0u8; 33];
552 let result = Address::from_bytes(bytes);
553 assert!(matches!(
554 result,
555 Err(AddressParseError::InvalidByteLength { actual: 33 })
556 ));
557 }
558
559 #[test]
560 fn to_short_string_formats() {
561 let address = Address::from_short_hex("0x2").unwrap();
562 assert_eq!(address.to_short_hex(), "0x2");
563 assert_eq!(address.to_raw_short_hex(), "2");
564
565 let zero = Address::ZERO;
566 assert_eq!(zero.to_short_hex(), "0x0");
567 assert_eq!(zero.to_raw_short_hex(), "0");
568 }
569
570 #[test]
571 fn to_canonical_string_formats() {
572 let address = Address::from_short_hex("0x2").unwrap();
573 assert_eq!(
574 address.to_canonical_string(true),
575 "0x0000000000000000000000000000000000000000000000000000000000000002"
576 );
577 assert_eq!(
578 address.to_canonical_string(false),
579 "0000000000000000000000000000000000000000000000000000000000000002"
580 );
581 }
582
583 #[test]
584 #[cfg(feature = "serde")]
585 fn formats() {
586 let actual = Address::from_short_hex("0x2").unwrap();
587
588 println!("{}", serde_json::to_string(&actual).unwrap());
589 println!("{:?}", bcs::to_bytes(&actual).unwrap());
590 let a: Address = serde_json::from_str("\"0x2\"").unwrap();
591 println!("{a}");
592 }
593}