sui_sdk_types/
address.rs

1/// Unique identifier for an Account on the Sui blockchain.
2///
3/// An `Address` is a 32-byte pseudonymous identifier used to uniquely identify an account and
4/// asset-ownership on the Sui blockchain. Often, human-readable addresses are encoded in
5/// hexadecimal with a `0x` prefix. For example, this is a valid Sui address:
6/// `0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331`.
7///
8/// ```
9/// use sui_sdk_types::Address;
10///
11/// let hex = "0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331";
12/// let address = Address::from_hex(hex).unwrap();
13/// println!("Address: {}", address);
14/// assert_eq!(hex, address.to_string());
15/// ```
16///
17/// # Deriving an Address
18///
19/// Addresses are cryptographically derived from a number of user account authenticators, the simplest
20/// of which is an [`Ed25519PublicKey`](crate::Ed25519PublicKey).
21///
22/// Deriving an address consists of the Blake2b256 hash of the sequence of bytes of its
23/// corresponding authenticator, prefixed with a domain-separator. For each authenticator, this
24/// domain-separator is the single byte-value of its [`SignatureScheme`](crate::SignatureScheme)
25/// flag. E.g. `hash(signature schema flag || authenticator bytes)`.
26///
27/// Each authenticator includes a convince method for deriving its `Address` as well as
28/// documentation for the specifics of how the derivation is done. See
29/// [`Ed25519PublicKey::derive_address`] for an example.
30///
31/// [`Ed25519PublicKey::derive_address`]: crate::Ed25519PublicKey::derive_address
32///
33/// ## Relationship to ObjectIds
34///
35/// [`ObjectId`]s and `Address`es share the same 32-byte addressable space but are derived
36/// leveraging different domain-separator values to ensure, cryptographically, that there won't be
37/// any overlap, e.g. there can't be a valid `Object` whose `ObjectId` is equal to that of the
38/// `Address` of a user account.
39///
40/// [`ObjectId`]: crate::ObjectId
41///
42/// # BCS
43///
44/// An `Address`'s BCS serialized form is defined by the following:
45///
46/// ```text
47/// address = 32OCTET
48/// ```
49#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
50#[cfg_attr(
51    feature = "serde",
52    derive(serde_derive::Serialize, serde_derive::Deserialize)
53)]
54#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
55pub struct Address(
56    #[cfg_attr(
57        feature = "serde",
58        serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable<ReadableAddress>>")
59    )]
60    [u8; Self::LENGTH],
61);
62
63impl Address {
64    pub const LENGTH: usize = 32;
65    pub const ZERO: Self = Self([0u8; Self::LENGTH]);
66    pub const TWO: Self = Self::from_u8(2);
67    pub const THREE: Self = Self::from_u8(3);
68
69    pub const fn new(bytes: [u8; Self::LENGTH]) -> Self {
70        Self(bytes)
71    }
72
73    const fn from_u8(byte: u8) -> Self {
74        let mut address = Self::ZERO;
75        address.0[31] = byte;
76        address
77    }
78
79    #[cfg(feature = "rand")]
80    #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
81    pub fn generate<R>(mut rng: R) -> Self
82    where
83        R: rand_core::RngCore + rand_core::CryptoRng,
84    {
85        let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
86        rng.fill_bytes(&mut buf);
87        Self::new(buf)
88    }
89
90    /// Return the underlying byte array of a Address.
91    pub const fn into_inner(self) -> [u8; Self::LENGTH] {
92        self.0
93    }
94
95    pub const fn inner(&self) -> &[u8; Self::LENGTH] {
96        &self.0
97    }
98
99    pub const fn as_bytes(&self) -> &[u8] {
100        &self.0
101    }
102
103    pub fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, AddressParseError> {
104        let hex = hex.as_ref();
105
106        if !hex.starts_with(b"0x") {
107            return Err(AddressParseError);
108        }
109
110        let hex = &hex[2..];
111
112        // If the string is too short we'll need to pad with 0's
113        if hex.len() < Self::LENGTH * 2 {
114            let mut buf = [b'0'; Self::LENGTH * 2];
115            let pad_length = (Self::LENGTH * 2) - hex.len();
116
117            buf[pad_length..].copy_from_slice(hex);
118
119            <[u8; Self::LENGTH] as hex::FromHex>::from_hex(buf)
120        } else {
121            <[u8; Self::LENGTH] as hex::FromHex>::from_hex(hex)
122        }
123        .map(Self)
124        //TODO fix error to contain hex parse error
125        .map_err(|_| AddressParseError)
126    }
127
128    pub fn to_hex(&self) -> String {
129        self.to_string()
130    }
131
132    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, AddressParseError> {
133        <[u8; Self::LENGTH]>::try_from(bytes.as_ref())
134            .map_err(|_| AddressParseError)
135            .map(Self)
136    }
137}
138
139impl std::str::FromStr for Address {
140    type Err = AddressParseError;
141
142    fn from_str(s: &str) -> Result<Self, Self::Err> {
143        Self::from_hex(s)
144    }
145}
146
147impl AsRef<[u8]> for Address {
148    fn as_ref(&self) -> &[u8] {
149        &self.0
150    }
151}
152
153impl AsRef<[u8; 32]> for Address {
154    fn as_ref(&self) -> &[u8; 32] {
155        &self.0
156    }
157}
158
159impl From<Address> for [u8; 32] {
160    fn from(address: Address) -> Self {
161        address.into_inner()
162    }
163}
164
165impl From<[u8; 32]> for Address {
166    fn from(address: [u8; 32]) -> Self {
167        Self::new(address)
168    }
169}
170
171impl From<Address> for Vec<u8> {
172    fn from(value: Address) -> Self {
173        value.0.to_vec()
174    }
175}
176
177impl From<super::ObjectId> for Address {
178    fn from(value: super::ObjectId) -> Self {
179        Self::new(value.into_inner())
180    }
181}
182
183impl std::fmt::Display for Address {
184    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185        write!(f, "0x")?;
186        for byte in &self.0 {
187            write!(f, "{:02x}", byte)?;
188        }
189
190        Ok(())
191    }
192}
193
194impl std::fmt::Debug for Address {
195    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196        f.debug_tuple("Address")
197            .field(&format_args!("\"{}\"", self))
198            .finish()
199    }
200}
201
202#[cfg(feature = "serde")]
203#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
204struct ReadableAddress;
205
206#[cfg(feature = "serde")]
207#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
208impl serde_with::SerializeAs<[u8; Address::LENGTH]> for ReadableAddress {
209    fn serialize_as<S>(source: &[u8; Address::LENGTH], serializer: S) -> Result<S::Ok, S::Error>
210    where
211        S: serde::Serializer,
212    {
213        let address = Address::new(*source);
214        serde_with::DisplayFromStr::serialize_as(&address, serializer)
215    }
216}
217
218#[cfg(feature = "serde")]
219#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
220impl<'de> serde_with::DeserializeAs<'de, [u8; Address::LENGTH]> for ReadableAddress {
221    fn deserialize_as<D>(deserializer: D) -> Result<[u8; Address::LENGTH], D::Error>
222    where
223        D: serde::Deserializer<'de>,
224    {
225        let address: Address = serde_with::DisplayFromStr::deserialize_as(deserializer)?;
226        Ok(address.into_inner())
227    }
228}
229
230#[derive(Clone, Copy, Debug, PartialEq, Eq)]
231pub struct AddressParseError;
232
233impl std::fmt::Display for AddressParseError {
234    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
235        write!(
236            f,
237            "Unable to parse Address (must be hex string of length {})",
238            Address::LENGTH
239        )
240    }
241}
242
243impl std::error::Error for AddressParseError {}
244
245#[cfg(test)]
246mod test {
247    use super::*;
248    use test_strategy::proptest;
249
250    #[cfg(target_arch = "wasm32")]
251    use wasm_bindgen_test::wasm_bindgen_test as test;
252
253    #[test]
254    fn hex_parsing() {
255        let actual = Address::from_hex("0x2").unwrap();
256        let expected = "0x0000000000000000000000000000000000000000000000000000000000000002";
257
258        assert_eq!(actual.to_string(), expected);
259    }
260
261    #[test]
262    #[cfg(feature = "serde")]
263    fn formats() {
264        let actual = Address::from_hex("0x2").unwrap();
265
266        println!("{}", serde_json::to_string(&actual).unwrap());
267        println!("{:?}", bcs::to_bytes(&actual).unwrap());
268        let a: Address = serde_json::from_str("\"0x2\"").unwrap();
269        println!("{a}");
270    }
271
272    #[proptest]
273    fn roundtrip_display_fromstr(address: Address) {
274        let s = address.to_string();
275        let a = s.parse::<Address>().unwrap();
276        assert_eq!(address, a);
277    }
278}