1use bech32::{self, FromBase32, ToBase32};
5use ed25519_dalek::{PublicKey, SecretKey, Keypair, Signer};
6use super::{Result, ElrondClientError};
7use rand::rngs::OsRng;
8
9#[derive(Clone, Debug, PartialEq)]
13pub struct ElrondAddress {
14 inner: String
15}
16
17fn check_elrond_address(addr_str: &str) -> Result<Option<PublicKey>> {
19 let (hrd, data) = bech32::decode(addr_str).map_err(|_| {
20 ElrondClientError::new("could not decode address from string")
21 })?;
22 if hrd == "erd" {
23 let public_key_bytes = Vec::<u8>::from_base32(&data).map_err(|_| {
24 ElrondClientError::new("could not convert base32 to bytes")
25 })?;
26 let public_key = PublicKey::from_bytes(&public_key_bytes).map_err(|_| {
27 ElrondClientError::new("bytes in bech32 are not a valid public key")
28 })?;
29 Ok(Some(public_key))
30 } else {
31 Ok(None)
32 }
33}
34
35impl ElrondAddress {
36 pub fn new(addr_str: &str) -> Result<Self> {
38 if let Some(_pk) = check_elrond_address(addr_str)? {
40 Ok(Self { inner: addr_str.to_string() })
41 }
42 else {
43 Err(ElrondClientError::new(
44 &format!(
45 "'{}' is not a valid elrond address",
46 addr_str
47 )
48 ))
49 }
50 }
51 pub fn to_public_key(&self) -> PublicKey {
53 check_elrond_address(&self.inner)
55 .expect("inner valid of elrond address corrupted (encoding)")
56 .expect("inner valid of elrond address corrupted (not elrond address)")
57 }
58 pub fn from_public_key(public_key: &PublicKey) -> Result<Self> {
60 let inner = bech32::encode("erd", public_key.to_base32()).map_err(|_| {
61 ElrondClientError::new("could not encode public key as bech32")
62 })?;
63 Ok(Self { inner })
64 }
65 pub fn to_string(&self) -> String {
67 self.inner.clone()
68 }
69}
70
71pub struct Account {
75 pub secret: SecretKey,
76 pub public: PublicKey,
77 pub address: ElrondAddress
78}
79
80impl Account {
81 pub fn generate() -> Result<Self> {
83 let mut csprng = OsRng{};
84 let secret = SecretKey::generate(&mut csprng);
85 let public = (&secret).into();
86 let address = ElrondAddress::from_public_key(&public)?;
87 Ok(Self {
88 secret,
89 public,
90 address
91 })
92 }
93 pub fn from_secret(secret: SecretKey) -> Result<Self> {
95 let public = (&secret).into();
96 let address = ElrondAddress::from_public_key(&public)?;
97 Ok(Self {
98 secret,
99 public,
100 address
101 })
102 }
103 pub fn sign(&self, data: &str) -> Result<String> {
105 let public_bytes = self.public.to_bytes();
106 let secret_bytes = self.secret.to_bytes();
107 let combined: Vec<u8> = secret_bytes.iter().chain(&public_bytes).map(|x| x.clone()).collect();
108 let keypair = Keypair::from_bytes(&combined).map_err(|_|{
111 ElrondClientError::new("could not load keypair from public and secret key data")
112 })?;
113 let signature = keypair.sign(data.as_bytes()).to_bytes();
114 assert_eq!(signature.len(), 64);
115 Ok(hex::encode(signature.to_vec()))
116 }
117 pub fn to_string(&self) -> String {
120 let secret_bytes = self.secret.to_bytes();
121 hex::encode(&secret_bytes.to_vec())
122 }
123 pub fn from_string(hex_str: &str) -> Result<Self> {
125 let bytes = hex::decode(hex_str).map_err(|_| {
126 ElrondClientError::new("could not decode hex string")
127 })?;
128 let secret = SecretKey::from_bytes(&bytes).map_err(|_| {
129 ElrondClientError::new("hex string bytes do not encode valid secret key")
130 })?;
131 Self::from_secret(secret)
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::{Account, ElrondAddress, SecretKey};
138 #[test]
139 fn generate_and_test_account() {
140 let account = Account::generate().unwrap();
141 let secret_bytes = &account.secret.to_bytes();
142 let secret_copy = SecretKey::from_bytes(secret_bytes).unwrap();
143 let account2 = Account::from_secret(secret_copy).unwrap();
144 assert_eq!(&account.secret.to_bytes(), &account2.secret.to_bytes());
145 assert_eq!(&account.public.to_bytes(), &account2.public.to_bytes());
146 assert_eq!(&account.address, &account2.address);
147 }
148
149 #[test]
150 fn validate_address(){
151 let addr_str = "erd16jats393r8rnut88yhvu5wvxxje57qzlj3tqk7n6jnf7f6cxs4uqfeh65k";
152 let address = ElrondAddress::new(addr_str).unwrap();
153 let public_key = address.to_public_key();
154 let address2 = ElrondAddress::from_public_key(&public_key).unwrap();
155 assert_eq!(address, address2);
156 }
157
158 #[test]
159 fn signing_completes(){
160 let private_key = "a4b36a5d97176618b5a7fcc9228d2fd98ee2f14ddd3d6462ae03e40eb487d15b";
161 let account = Account::from_string(private_key).unwrap();
162 let sig = account.sign("dummy data").unwrap();
163 assert_eq!(sig, "a25d1b1e24cd9299396e0c6e191b80a8e4f54e19c495955f13d6c168e5784dd642f540938333851fb1abcaa6d13f327ac2341607ad2fbb941dfdeeb6c4fcd803");
164 }
165
166 #[test]
167 fn save_and_load_account(){
168 let account = Account::generate().unwrap();
169 let account_as_string = account.to_string();
170 println!("{}", &account_as_string);
171 let account_copy = Account::from_string(&account_as_string).unwrap();
172 assert_eq!(&account.secret.to_bytes(), &account_copy.secret.to_bytes());
173 assert_eq!(&account.public.to_bytes(), &account_copy.public.to_bytes());
174 assert_eq!(account.address.to_string(), account_copy.address.to_string());
175 }
176
177 #[test]
178 fn address_from_private_key(){
179 let private_key = "a4b36a5d97176618b5a7fcc9228d2fd98ee2f14ddd3d6462ae03e40eb487d15b";
180 let account = Account::from_string(private_key).unwrap();
181 assert_eq!("erd146apxa83wr7paz3gsg07dhcpg98ascjtpg9p8l8g5rpmg6chhchq9ccvmc", &account.address.to_string());
182 }
183
184}