sos_core/
account.rs

1use crate::{Error, Result};
2use rand::Rng;
3use serde::{Deserialize, Serialize};
4use std::{fmt, str::FromStr};
5
6/// Account identifier.
7///
8/// String encoding starts with 0x and is followed with
9/// 20 bytes hex-encoded.
10#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, Hash, Eq, PartialEq)]
11#[serde(try_from = "String", into = "String")]
12pub struct AccountId([u8; 20]);
13
14impl AccountId {
15    /// Create a random account identifier.
16    pub fn random() -> Self {
17        let mut rng = crate::csprng();
18        Self(rng.gen())
19    }
20}
21
22impl fmt::Display for AccountId {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        write!(f, "0x{}", hex::encode(self.0))
25    }
26}
27
28impl AsRef<[u8]> for AccountId {
29    fn as_ref(&self) -> &[u8] {
30        &self.0
31    }
32}
33
34impl From<[u8; 20]> for AccountId {
35    fn from(value: [u8; 20]) -> Self {
36        Self(value)
37    }
38}
39
40impl FromStr for AccountId {
41    type Err = Error;
42
43    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
44        if !s.starts_with("0x") {
45            return Err(Error::BadAccountIdPrefix);
46        }
47        let bytes = hex::decode(&s[2..])?;
48        let buffer: [u8; 20] = bytes.as_slice().try_into()?;
49        Ok(AccountId(buffer))
50    }
51}
52
53impl From<AccountId> for String {
54    fn from(value: AccountId) -> String {
55        value.to_string()
56    }
57}
58
59impl From<AccountId> for [u8; 20] {
60    fn from(value: AccountId) -> [u8; 20] {
61        value.0
62    }
63}
64
65impl TryFrom<String> for AccountId {
66    type Error = Error;
67    fn try_from(value: String) -> Result<Self> {
68        <AccountId as FromStr>::from_str(&value)
69    }
70}