aptos_sdk/types/
address.rs1use crate::error::{AptosError, AptosResult};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use std::fmt;
9use std::str::FromStr;
10
11pub const ADDRESS_LENGTH: usize = 32;
13
14#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct AccountAddress([u8; ADDRESS_LENGTH]);
45
46impl AccountAddress {
47 pub const ZERO: Self = Self([0u8; ADDRESS_LENGTH]);
49
50 pub const ONE: Self = Self::from_u64(1);
52
53 pub const THREE: Self = Self::from_u64(3);
55
56 pub const FOUR: Self = Self::from_u64(4);
58
59 pub const A: Self = Self::from_u64(10);
61
62 pub const fn new(bytes: [u8; ADDRESS_LENGTH]) -> Self {
64 Self(bytes)
65 }
66
67 const fn from_u64(value: u64) -> Self {
69 let mut bytes = [0u8; ADDRESS_LENGTH];
70 let value_bytes = value.to_be_bytes();
71 bytes[ADDRESS_LENGTH - 8] = value_bytes[0];
72 bytes[ADDRESS_LENGTH - 7] = value_bytes[1];
73 bytes[ADDRESS_LENGTH - 6] = value_bytes[2];
74 bytes[ADDRESS_LENGTH - 5] = value_bytes[3];
75 bytes[ADDRESS_LENGTH - 4] = value_bytes[4];
76 bytes[ADDRESS_LENGTH - 3] = value_bytes[5];
77 bytes[ADDRESS_LENGTH - 2] = value_bytes[6];
78 bytes[ADDRESS_LENGTH - 1] = value_bytes[7];
79 Self(bytes)
80 }
81
82 pub fn from_hex<T: AsRef<[u8]>>(hex_str: T) -> AptosResult<Self> {
93 let hex_str = hex_str.as_ref();
94
95 if hex_str.is_empty() {
97 return Err(AptosError::InvalidAddress(
98 "address cannot be empty".to_string(),
99 ));
100 }
101
102 let hex_str = if hex_str.starts_with(b"0x") || hex_str.starts_with(b"0X") {
103 &hex_str[2..]
104 } else {
105 hex_str
106 };
107
108 let hex_string =
110 std::str::from_utf8(hex_str).map_err(|e| AptosError::InvalidAddress(e.to_string()))?;
111
112 if hex_string.is_empty() {
114 return Err(AptosError::InvalidAddress(
115 "address must contain at least one hex digit".to_string(),
116 ));
117 }
118
119 if hex_string.len() > ADDRESS_LENGTH * 2 {
120 return Err(AptosError::InvalidAddress(format!(
121 "address too long: {} characters (max {})",
122 hex_string.len(),
123 ADDRESS_LENGTH * 2
124 )));
125 }
126
127 let padded = format!("{hex_string:0>64}");
129 let bytes = hex::decode(&padded)?;
130
131 let mut address = [0u8; ADDRESS_LENGTH];
132 address.copy_from_slice(&bytes);
133 Ok(Self(address))
134 }
135
136 pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> AptosResult<Self> {
142 let bytes = bytes.as_ref();
143 if bytes.len() != ADDRESS_LENGTH {
144 return Err(AptosError::InvalidAddress(format!(
145 "expected {} bytes, got {}",
146 ADDRESS_LENGTH,
147 bytes.len()
148 )));
149 }
150 let mut address = [0u8; ADDRESS_LENGTH];
151 address.copy_from_slice(bytes);
152 Ok(Self(address))
153 }
154
155 #[inline]
157 pub fn as_bytes(&self) -> &[u8] {
158 &self.0
159 }
160
161 #[inline]
163 pub fn to_bytes(&self) -> [u8; ADDRESS_LENGTH] {
164 self.0
165 }
166
167 pub fn to_hex(&self) -> String {
171 self.to_long_string()
172 }
173
174 pub fn to_long_string(&self) -> String {
179 format!("0x{}", hex::encode(self.0))
180 }
181
182 pub fn to_short_string(&self) -> String {
186 let hex = hex::encode(self.0);
187 let trimmed = hex.trim_start_matches('0');
188 if trimmed.is_empty() {
189 "0x0".to_string()
190 } else {
191 format!("0x{trimmed}")
192 }
193 }
194
195 pub fn to_standard_string(&self) -> String {
200 if self.is_special() {
201 self.to_short_string()
202 } else {
203 self.to_long_string()
204 }
205 }
206
207 #[inline]
209 pub fn is_zero(&self) -> bool {
210 self == &Self::ZERO
211 }
212
213 #[inline]
218 pub fn is_special(&self) -> bool {
219 self.0[..ADDRESS_LENGTH - 1].iter().all(|&b| b == 0)
220 && self.0[ADDRESS_LENGTH - 1] > 0
221 && self.0[ADDRESS_LENGTH - 1] < 16
222 }
223}
224
225impl Default for AccountAddress {
226 fn default() -> Self {
227 Self::ZERO
228 }
229}
230
231impl fmt::Debug for AccountAddress {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "AccountAddress({})", self.to_short_string())
234 }
235}
236
237impl fmt::Display for AccountAddress {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 write!(f, "{}", self.to_standard_string())
243 }
244}
245
246impl FromStr for AccountAddress {
247 type Err = AptosError;
248
249 fn from_str(s: &str) -> Result<Self, Self::Err> {
250 Self::from_hex(s)
251 }
252}
253
254impl Serialize for AccountAddress {
255 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
256 where
257 S: Serializer,
258 {
259 if serializer.is_human_readable() {
260 serializer.serialize_str(&self.to_hex())
261 } else {
262 use serde::ser::SerializeTuple;
265 let mut tuple = serializer.serialize_tuple(ADDRESS_LENGTH)?;
266 for byte in &self.0 {
267 tuple.serialize_element(byte)?;
268 }
269 tuple.end()
270 }
271 }
272}
273
274impl<'de> Deserialize<'de> for AccountAddress {
275 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
276 where
277 D: Deserializer<'de>,
278 {
279 if deserializer.is_human_readable() {
280 let s = String::deserialize(deserializer)?;
281 Self::from_hex(&s).map_err(serde::de::Error::custom)
282 } else {
283 let bytes = <[u8; ADDRESS_LENGTH]>::deserialize(deserializer)?;
284 Ok(Self(bytes))
285 }
286 }
287}
288
289impl From<[u8; ADDRESS_LENGTH]> for AccountAddress {
290 fn from(bytes: [u8; ADDRESS_LENGTH]) -> Self {
291 Self(bytes)
292 }
293}
294
295impl From<AccountAddress> for [u8; ADDRESS_LENGTH] {
296 fn from(addr: AccountAddress) -> Self {
297 addr.0
298 }
299}
300
301impl AsRef<[u8]> for AccountAddress {
302 fn as_ref(&self) -> &[u8] {
303 &self.0
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn test_from_hex() {
313 let addr = AccountAddress::from_hex(
315 "0x0000000000000000000000000000000000000000000000000000000000000001",
316 )
317 .unwrap();
318 assert_eq!(addr, AccountAddress::ONE);
319
320 let addr = AccountAddress::from_hex("0x1").unwrap();
322 assert_eq!(addr, AccountAddress::ONE);
323
324 let addr = AccountAddress::from_hex("1").unwrap();
326 assert_eq!(addr, AccountAddress::ONE);
327 }
328
329 #[test]
330 fn test_to_string() {
331 assert_eq!(AccountAddress::ONE.to_string(), "0x1");
333 assert_eq!(AccountAddress::THREE.to_string(), "0x3");
334 assert_eq!(AccountAddress::FOUR.to_string(), "0x4");
335 assert_eq!(AccountAddress::A.to_string(), "0xa");
336
337 assert_eq!(
339 AccountAddress::ZERO.to_string(),
340 "0x0000000000000000000000000000000000000000000000000000000000000000"
341 );
342
343 assert_eq!(AccountAddress::ONE.to_short_string(), "0x1");
345 assert_eq!(
346 AccountAddress::ONE.to_long_string(),
347 "0x0000000000000000000000000000000000000000000000000000000000000001"
348 );
349 assert_eq!(AccountAddress::ZERO.to_short_string(), "0x0");
350 }
351
352 #[test]
353 fn test_special_addresses() {
354 assert!(AccountAddress::ONE.is_special());
355 assert!(AccountAddress::THREE.is_special());
356 assert!(AccountAddress::FOUR.is_special());
357 assert!(AccountAddress::A.is_special());
358 assert!(!AccountAddress::ZERO.is_special());
359 }
360
361 #[test]
362 fn test_json_serialization() {
363 let addr = AccountAddress::ONE;
364 let json = serde_json::to_string(&addr).unwrap();
365 assert_eq!(
366 json,
367 "\"0x0000000000000000000000000000000000000000000000000000000000000001\""
368 );
369
370 let parsed: AccountAddress = serde_json::from_str(&json).unwrap();
371 assert_eq!(parsed, addr);
372 }
373
374 #[test]
375 fn test_from_str() {
376 let addr: AccountAddress = "0x1".parse().unwrap();
377 assert_eq!(addr, AccountAddress::ONE);
378 }
379
380 #[test]
381 fn test_from_bytes() {
382 let bytes = [0u8; ADDRESS_LENGTH];
383 let addr = AccountAddress::new(bytes);
384 assert_eq!(addr, AccountAddress::ZERO);
385 }
386
387 #[test]
388 fn test_as_bytes() {
389 let addr = AccountAddress::ONE;
390 let bytes = addr.as_bytes();
391 assert_eq!(bytes.len(), ADDRESS_LENGTH);
392 assert_eq!(bytes[ADDRESS_LENGTH - 1], 1);
393 }
394
395 #[test]
396 fn test_is_zero() {
397 assert!(AccountAddress::ZERO.is_zero());
398 assert!(!AccountAddress::ONE.is_zero());
399 }
400
401 #[test]
402 fn test_debug() {
403 let addr = AccountAddress::ONE;
404 let debug = format!("{addr:?}");
405 assert!(debug.contains("AccountAddress"));
406 }
407
408 #[test]
409 fn test_display() {
410 let addr = AccountAddress::ONE;
412 let display = format!("{addr}");
413 assert_eq!(display, "0x1");
414
415 let mut bytes = [0u8; ADDRESS_LENGTH];
417 bytes[0] = 0xab;
418 bytes[ADDRESS_LENGTH - 1] = 0xcd;
419 let addr = AccountAddress::new(bytes);
420 let display = format!("{addr}");
421 assert!(display.starts_with("0x"));
422 assert_eq!(display.len(), 66); }
424
425 #[test]
426 fn test_from_hex_uppercase() {
427 let addr = AccountAddress::from_hex("0X1").unwrap();
428 assert_eq!(addr, AccountAddress::ONE);
429 }
430
431 #[test]
432 fn test_from_hex_invalid() {
433 let result = AccountAddress::from_hex("not_hex");
434 assert!(result.is_err());
435 }
436
437 #[test]
438 fn test_into_array() {
439 let addr = AccountAddress::new([42u8; ADDRESS_LENGTH]);
440 let bytes: [u8; ADDRESS_LENGTH] = addr.into();
441 assert_eq!(bytes, [42u8; ADDRESS_LENGTH]);
442 }
443
444 #[test]
445 fn test_as_ref() {
446 let addr = AccountAddress::ONE;
447 let slice: &[u8] = addr.as_ref();
448 assert_eq!(slice.len(), ADDRESS_LENGTH);
449 }
450
451 #[test]
452 fn test_equality() {
453 assert_eq!(AccountAddress::ONE, AccountAddress::ONE);
454 assert_ne!(AccountAddress::ONE, AccountAddress::THREE);
455 }
456
457 #[test]
458 fn test_hash() {
459 use std::collections::HashSet;
460 let mut set = HashSet::new();
461 set.insert(AccountAddress::ONE);
462 set.insert(AccountAddress::THREE);
463 assert_eq!(set.len(), 2);
464 assert!(set.contains(&AccountAddress::ONE));
465 }
466
467 #[test]
468 fn test_from_array() {
469 let bytes = [0x12u8; ADDRESS_LENGTH];
470 let addr: AccountAddress = bytes.into();
471 assert_eq!(addr.as_bytes(), &bytes);
472 }
473
474 #[test]
475 fn test_bcs_serialization() {
476 let addr = AccountAddress::ONE;
477 let serialized = aptos_bcs::to_bytes(&addr).unwrap();
478 let deserialized: AccountAddress = aptos_bcs::from_bytes(&serialized).unwrap();
479 assert_eq!(addr, deserialized);
480 }
481
482 #[test]
483 fn test_bcs_serialization_roundtrip_all_special() {
484 let addresses = [
485 AccountAddress::ZERO,
486 AccountAddress::ONE,
487 AccountAddress::THREE,
488 AccountAddress::FOUR,
489 AccountAddress::A,
490 ];
491
492 for addr in &addresses {
493 let serialized = aptos_bcs::to_bytes(addr).unwrap();
494 let deserialized: AccountAddress = aptos_bcs::from_bytes(&serialized).unwrap();
495 assert_eq!(addr, &deserialized);
496 }
497 }
498
499 #[test]
500 fn test_from_hex_too_long() {
501 let long_hex = "0x".to_string() + &"a".repeat(65);
503 let result = AccountAddress::from_hex(&long_hex);
504 assert!(result.is_err());
505 }
506
507 #[test]
508 fn test_from_hex_empty() {
509 let result = AccountAddress::from_hex("");
510 assert!(result.is_err());
511 }
512
513 #[test]
514 fn test_from_hex_just_prefix() {
515 let result = AccountAddress::from_hex("0x");
516 assert!(result.is_err());
517 }
518
519 #[test]
520 fn test_from_hex_with_leading_zeros() {
521 let addr = AccountAddress::from_hex("0x0000000000000001").unwrap();
522 assert_eq!(addr, AccountAddress::ONE);
523 }
524
525 #[test]
526 fn test_short_string_non_special() {
527 let mut bytes = [0u8; ADDRESS_LENGTH];
529 bytes[0] = 0xab;
530 bytes[ADDRESS_LENGTH - 1] = 0xcd;
531 let addr = AccountAddress::new(bytes);
532
533 let short = addr.to_short_string();
535 assert!(short.starts_with("0x"));
536 assert_eq!(short.len(), 66);
538 }
539
540 #[test]
541 fn test_to_hex() {
542 let addr = AccountAddress::ONE;
543 let hex = addr.to_hex();
544 assert!(hex.starts_with("0x"));
545 assert_eq!(hex.len(), 66);
546 assert!(hex.ends_with('1'));
547 }
548
549 #[test]
550 fn test_json_deserialization_short() {
551 let json = "\"0x1\"";
553 let addr: AccountAddress = serde_json::from_str(json).unwrap();
554 assert_eq!(addr, AccountAddress::ONE);
555 }
556
557 #[test]
558 fn test_clone() {
559 let addr = AccountAddress::ONE;
560 let cloned = addr;
562 assert_eq!(addr, cloned);
563 }
564
565 #[test]
566 fn test_copy() {
567 let addr = AccountAddress::ONE;
568 let copied = addr; assert_eq!(addr, copied);
570 }
571
572 #[test]
573 fn test_default() {
574 let addr = AccountAddress::default();
575 assert_eq!(addr, AccountAddress::ZERO);
576 }
577
578 #[test]
579 fn test_from_hex_mixed_case() {
580 let addr1 = AccountAddress::from_hex("0xAbCdEf").unwrap();
581 let addr2 = AccountAddress::from_hex("0xabcdef").unwrap();
582 let addr3 = AccountAddress::from_hex("0xABCDEF").unwrap();
583 assert_eq!(addr1, addr2);
584 assert_eq!(addr2, addr3);
585 }
586
587 #[test]
588 fn test_special_address_boundary() {
589 let mut bytes = [0u8; ADDRESS_LENGTH];
591 bytes[14] = 1; let addr = AccountAddress::new(bytes);
593 assert!(!addr.is_special());
594
595 let mut bytes = [0u8; ADDRESS_LENGTH];
597 bytes[ADDRESS_LENGTH - 1] = 0x0f; let addr = AccountAddress::new(bytes);
599 assert!(addr.is_special());
600
601 let mut bytes = [0u8; ADDRESS_LENGTH];
603 bytes[ADDRESS_LENGTH - 1] = 0x10; let addr = AccountAddress::new(bytes);
605 assert!(!addr.is_special());
606
607 let addr = AccountAddress::ZERO;
609 assert!(!addr.is_special());
610 }
611
612 #[test]
613 fn test_from_bytes_wrong_length() {
614 let short = [0u8; 16];
616 let result = AccountAddress::from_bytes(short);
617 assert!(result.is_err());
618 assert!(
619 result
620 .unwrap_err()
621 .to_string()
622 .contains("expected 32 bytes")
623 );
624
625 let long = [0u8; 64];
627 let result = AccountAddress::from_bytes(long);
628 assert!(result.is_err());
629
630 let empty: [u8; 0] = [];
632 let result = AccountAddress::from_bytes(empty);
633 assert!(result.is_err());
634 }
635
636 #[test]
637 fn test_from_bytes_valid() {
638 let bytes = [0xab; ADDRESS_LENGTH];
639 let addr = AccountAddress::from_bytes(bytes).unwrap();
640 assert_eq!(addr.as_bytes(), &bytes);
641 }
642}