1use alloc::{format, string::String};
2use core::{
3 fmt::{Debug, Display},
4 str::FromStr,
5};
6
7use crate::{
8 convert::{decode, encode},
9 ed25519,
10 error::DecodeError,
11 version,
12};
13
14#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
15#[cfg_attr(
16 feature = "serde",
17 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
18)]
19pub enum Strkey {
20 PublicKeyEd25519(ed25519::PublicKey),
21 PrivateKeyEd25519(ed25519::PrivateKey),
22 PreAuthTx(PreAuthTx),
23 HashX(HashX),
24 MuxedAccountEd25519(ed25519::MuxedAccount),
25 SignedPayloadEd25519(ed25519::SignedPayload),
26 Contract(Contract),
27 LiquidityPool(LiquidityPool),
28 ClaimableBalance(ClaimableBalance),
29}
30
31impl Strkey {
32 pub fn to_string(&self) -> String {
33 match self {
34 Self::PublicKeyEd25519(x) => x.to_string(),
35 Self::PrivateKeyEd25519(x) => x.to_string(),
36 Self::PreAuthTx(x) => x.to_string(),
37 Self::HashX(x) => x.to_string(),
38 Self::MuxedAccountEd25519(x) => x.to_string(),
39 Self::SignedPayloadEd25519(x) => x.to_string(),
40 Self::Contract(x) => x.to_string(),
41 Self::LiquidityPool(x) => x.to_string(),
42 Self::ClaimableBalance(x) => x.to_string(),
43 }
44 }
45
46 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
47 let (ver, payload) = decode(s)?;
48 match ver {
49 version::PUBLIC_KEY_ED25519 => Ok(Self::PublicKeyEd25519(
50 ed25519::PublicKey::from_payload(&payload)?,
51 )),
52 version::PRIVATE_KEY_ED25519 => Ok(Self::PrivateKeyEd25519(
53 ed25519::PrivateKey::from_payload(&payload)?,
54 )),
55 version::PRE_AUTH_TX => Ok(Self::PreAuthTx(PreAuthTx::from_payload(&payload)?)),
56 version::HASH_X => Ok(Self::HashX(HashX::from_payload(&payload)?)),
57 version::MUXED_ACCOUNT_ED25519 => Ok(Self::MuxedAccountEd25519(
58 ed25519::MuxedAccount::from_payload(&payload)?,
59 )),
60 version::SIGNED_PAYLOAD_ED25519 => Ok(Self::SignedPayloadEd25519(
61 ed25519::SignedPayload::from_payload(&payload)?,
62 )),
63 version::CONTRACT => Ok(Self::Contract(Contract::from_payload(&payload)?)),
64 version::LIQUIDITY_POOL => {
65 Ok(Self::LiquidityPool(LiquidityPool::from_payload(&payload)?))
66 }
67 version::CLAIMABLE_BALANCE => Ok(Self::ClaimableBalance(
68 ClaimableBalance::from_payload(&payload)?,
69 )),
70 _ => Err(DecodeError::Invalid),
71 }
72 }
73}
74
75impl Display for Strkey {
76 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77 write!(f, "{}", self.to_string())
78 }
79}
80
81impl FromStr for Strkey {
82 type Err = DecodeError;
83
84 fn from_str(s: &str) -> Result<Self, Self::Err> {
85 Strkey::from_string(s)
86 }
87}
88
89#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
90#[cfg_attr(
91 feature = "serde",
92 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
93)]
94pub struct PreAuthTx(pub [u8; 32]);
95
96impl Debug for PreAuthTx {
97 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98 write!(f, "PreAuthTx(")?;
99 write!(
100 f,
101 "{}",
102 &self
103 .0
104 .iter()
105 .map(|b| format!("{b:02x}"))
106 .collect::<String>()
107 )?;
108 write!(f, ")")?;
109 Ok(())
110 }
111}
112
113impl PreAuthTx {
114 pub fn to_string(&self) -> String {
115 encode(version::PRE_AUTH_TX, &self.0)
116 }
117
118 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
119 Ok(Self(payload.try_into().map_err(|_| DecodeError::Invalid)?))
120 }
121
122 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
123 let (ver, payload) = decode(s)?;
124 match ver {
125 version::PRE_AUTH_TX => Self::from_payload(&payload),
126 _ => Err(DecodeError::Invalid),
127 }
128 }
129}
130
131impl Display for PreAuthTx {
132 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
133 write!(f, "{}", self.to_string())
134 }
135}
136
137impl FromStr for PreAuthTx {
138 type Err = DecodeError;
139
140 fn from_str(s: &str) -> Result<Self, Self::Err> {
141 PreAuthTx::from_string(s)
142 }
143}
144
145#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
146#[cfg_attr(
147 feature = "serde",
148 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
149)]
150pub struct HashX(pub [u8; 32]);
151
152impl Debug for HashX {
153 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
154 write!(f, "HashX(")?;
155 write!(
156 f,
157 "{}",
158 &self
159 .0
160 .iter()
161 .map(|b| format!("{b:02x}"))
162 .collect::<String>()
163 )?;
164 write!(f, ")")?;
165 Ok(())
166 }
167}
168
169impl HashX {
170 pub fn to_string(&self) -> String {
171 encode(version::HASH_X, &self.0)
172 }
173
174 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
175 Ok(Self(payload.try_into().map_err(|_| DecodeError::Invalid)?))
176 }
177
178 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
179 let (ver, payload) = decode(s)?;
180 match ver {
181 version::HASH_X => Self::from_payload(&payload),
182 _ => Err(DecodeError::Invalid),
183 }
184 }
185}
186
187impl Display for HashX {
188 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189 write!(f, "{}", self.to_string())
190 }
191}
192
193impl FromStr for HashX {
194 type Err = DecodeError;
195
196 fn from_str(s: &str) -> Result<Self, Self::Err> {
197 HashX::from_string(s)
198 }
199}
200
201#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
202#[cfg_attr(
203 feature = "serde",
204 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
205)]
206pub struct Contract(pub [u8; 32]);
207
208impl Debug for Contract {
209 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
210 write!(f, "Contract(")?;
211 write!(
212 f,
213 "{}",
214 &self
215 .0
216 .iter()
217 .map(|b| format!("{b:02x}"))
218 .collect::<String>()
219 )?;
220 write!(f, ")")?;
221 Ok(())
222 }
223}
224
225impl Contract {
226 pub fn to_string(&self) -> String {
227 encode(version::CONTRACT, &self.0)
228 }
229
230 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
231 Ok(Self(payload.try_into().map_err(|_| DecodeError::Invalid)?))
232 }
233
234 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
235 let (ver, payload) = decode(s)?;
236 match ver {
237 version::CONTRACT => Self::from_payload(&payload),
238 _ => Err(DecodeError::Invalid),
239 }
240 }
241}
242
243impl Display for Contract {
244 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245 write!(f, "{}", self.to_string())
246 }
247}
248
249impl FromStr for Contract {
250 type Err = DecodeError;
251
252 fn from_str(s: &str) -> Result<Self, Self::Err> {
253 Contract::from_string(s)
254 }
255}
256
257#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
258pub struct LiquidityPool(pub [u8; 32]);
259
260impl Debug for LiquidityPool {
261 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
262 write!(f, "LiquidityPool(")?;
263 write!(
264 f,
265 "{}",
266 &self
267 .0
268 .iter()
269 .map(|b| format!("{b:02x}"))
270 .collect::<String>()
271 )?;
272 write!(f, ")")?;
273 Ok(())
274 }
275}
276
277impl LiquidityPool {
278 pub fn to_string(&self) -> String {
279 encode(version::LIQUIDITY_POOL, &self.0)
280 }
281
282 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
283 Ok(Self(payload.try_into().map_err(|_| DecodeError::Invalid)?))
284 }
285
286 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
287 let (ver, payload) = decode(s)?;
288 match ver {
289 version::LIQUIDITY_POOL => Self::from_payload(&payload),
290 _ => Err(DecodeError::Invalid),
291 }
292 }
293}
294
295impl Display for LiquidityPool {
296 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
297 write!(f, "{}", self.to_string())
298 }
299}
300
301impl FromStr for LiquidityPool {
302 type Err = DecodeError;
303
304 fn from_str(s: &str) -> Result<Self, Self::Err> {
305 LiquidityPool::from_string(s)
306 }
307}
308
309#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
310pub enum ClaimableBalance {
311 V0([u8; 32]),
312}
313
314impl Debug for ClaimableBalance {
315 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
316 write!(f, "ClaimableBalance(")?;
317 match self {
318 Self::V0(v0) => {
319 write!(
320 f,
321 "V0({})",
322 &v0.iter().map(|b| format!("{b:02x}")).collect::<String>()
323 )?;
324 }
325 }
326 write!(f, ")")?;
327 Ok(())
328 }
329}
330
331impl ClaimableBalance {
332 pub fn to_string(&self) -> String {
333 match self {
334 Self::V0(v0) => {
335 let mut payload = [0; 33];
337 payload[1..].copy_from_slice(v0);
338 encode(version::CLAIMABLE_BALANCE, &payload)
339 }
340 }
341 }
342
343 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
344 match payload {
345 [0, rest @ ..] => Ok(Self::V0(rest.try_into().map_err(|_| DecodeError::Invalid)?)),
347 _ => Err(DecodeError::Invalid),
348 }
349 }
350
351 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
352 let (ver, payload) = decode(s)?;
353 match ver {
354 version::CLAIMABLE_BALANCE => Self::from_payload(&payload),
355 _ => Err(DecodeError::Invalid),
356 }
357 }
358}
359
360impl Display for ClaimableBalance {
361 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
362 write!(f, "{}", self.to_string())
363 }
364}
365
366impl FromStr for ClaimableBalance {
367 type Err = DecodeError;
368
369 fn from_str(s: &str) -> Result<Self, Self::Err> {
370 ClaimableBalance::from_string(s)
371 }
372}