1use core::{
2 fmt::{Debug, Display},
3 str::FromStr,
4};
5
6use heapless::String as HeaplessString;
7
8use crate::{
9 convert::{binary_len, decode, encode, encode_len},
10 ed25519,
11 error::DecodeError,
12 version,
13};
14
15#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
20#[cfg_attr(
21 feature = "serde",
22 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
23)]
24pub enum Strkey {
25 PublicKeyEd25519(ed25519::PublicKey),
26 PreAuthTx(PreAuthTx),
27 HashX(HashX),
28 MuxedAccountEd25519(ed25519::MuxedAccount),
29 SignedPayloadEd25519(ed25519::SignedPayload),
30 Contract(Contract),
31 LiquidityPool(LiquidityPool),
32 ClaimableBalance(ClaimableBalance),
33}
34
35impl Strkey {
36 const MAX_PAYLOAD_LEN: usize = ed25519::SignedPayload::MAX_PAYLOAD_LEN;
38 const MAX_BINARY_LEN: usize = binary_len(Self::MAX_PAYLOAD_LEN);
39 pub const MAX_ENCODED_LEN: usize = encode_len(Self::MAX_BINARY_LEN);
40 const _ASSERTS: () = {
41 assert!(Self::MAX_PAYLOAD_LEN == 100);
42 assert!(Self::MAX_BINARY_LEN == 103);
43 assert!(Self::MAX_ENCODED_LEN == 165);
44 assert!(Self::MAX_PAYLOAD_LEN >= ed25519::PrivateKey::PAYLOAD_LEN);
46 assert!(Self::MAX_PAYLOAD_LEN >= ed25519::PublicKey::PAYLOAD_LEN);
47 assert!(Self::MAX_PAYLOAD_LEN >= ed25519::MuxedAccount::PAYLOAD_LEN);
48 assert!(Self::MAX_PAYLOAD_LEN >= ed25519::SignedPayload::MAX_PAYLOAD_LEN);
49 assert!(Self::MAX_PAYLOAD_LEN >= PreAuthTx::PAYLOAD_LEN);
50 assert!(Self::MAX_PAYLOAD_LEN >= HashX::PAYLOAD_LEN);
51 assert!(Self::MAX_PAYLOAD_LEN >= Contract::PAYLOAD_LEN);
52 assert!(Self::MAX_PAYLOAD_LEN >= LiquidityPool::PAYLOAD_LEN);
53 assert!(Self::MAX_PAYLOAD_LEN >= ClaimableBalance::PAYLOAD_LEN);
54 assert!(Self::MAX_BINARY_LEN >= ed25519::PrivateKey::BINARY_LEN);
56 assert!(Self::MAX_BINARY_LEN >= ed25519::PublicKey::BINARY_LEN);
57 assert!(Self::MAX_BINARY_LEN >= ed25519::MuxedAccount::BINARY_LEN);
58 assert!(Self::MAX_BINARY_LEN >= ed25519::SignedPayload::MAX_BINARY_LEN);
59 assert!(Self::MAX_BINARY_LEN >= PreAuthTx::BINARY_LEN);
60 assert!(Self::MAX_BINARY_LEN >= HashX::BINARY_LEN);
61 assert!(Self::MAX_BINARY_LEN >= Contract::BINARY_LEN);
62 assert!(Self::MAX_BINARY_LEN >= LiquidityPool::BINARY_LEN);
63 assert!(Self::MAX_BINARY_LEN >= ClaimableBalance::BINARY_LEN);
64 assert!(Self::MAX_ENCODED_LEN >= ed25519::PrivateKey::ENCODED_LEN);
66 assert!(Self::MAX_ENCODED_LEN >= ed25519::PublicKey::ENCODED_LEN);
67 assert!(Self::MAX_ENCODED_LEN >= ed25519::MuxedAccount::ENCODED_LEN);
68 assert!(Self::MAX_ENCODED_LEN >= ed25519::SignedPayload::MAX_ENCODED_LEN);
69 assert!(Self::MAX_ENCODED_LEN >= PreAuthTx::ENCODED_LEN);
70 assert!(Self::MAX_ENCODED_LEN >= HashX::ENCODED_LEN);
71 assert!(Self::MAX_ENCODED_LEN >= Contract::ENCODED_LEN);
72 assert!(Self::MAX_ENCODED_LEN >= LiquidityPool::ENCODED_LEN);
73 assert!(Self::MAX_ENCODED_LEN >= ClaimableBalance::ENCODED_LEN);
74 };
75
76 pub fn to_string(&self) -> HeaplessString<{ Self::MAX_ENCODED_LEN }> {
77 let mut s: HeaplessString<{ Self::MAX_ENCODED_LEN }> = HeaplessString::new();
78 match self {
79 Self::PublicKeyEd25519(x) => s.push_str(x.to_string().as_str()).unwrap(),
80 Self::PreAuthTx(x) => s.push_str(x.to_string().as_str()).unwrap(),
81 Self::HashX(x) => s.push_str(x.to_string().as_str()).unwrap(),
82 Self::MuxedAccountEd25519(x) => s.push_str(x.to_string().as_str()).unwrap(),
83 Self::SignedPayloadEd25519(x) => s.push_str(x.to_string().as_str()).unwrap(),
84 Self::Contract(x) => s.push_str(x.to_string().as_str()).unwrap(),
85 Self::LiquidityPool(x) => s.push_str(x.to_string().as_str()).unwrap(),
86 Self::ClaimableBalance(x) => s.push_str(x.to_string().as_str()).unwrap(),
87 }
88 s
89 }
90
91 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
92 Self::from_slice(s.as_bytes())
93 }
94
95 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
96 if s.first() == Some(&b'S') {
100 return Err(DecodeError::PrivateKey);
101 }
102 let (ver, payload) = decode::<{ Self::MAX_PAYLOAD_LEN }, { Self::MAX_BINARY_LEN }>(s)?;
103 match ver {
104 version::PUBLIC_KEY_ED25519 => Ok(Self::PublicKeyEd25519(
105 ed25519::PublicKey::from_payload(&payload)?,
106 )),
107 version::PRE_AUTH_TX => Ok(Self::PreAuthTx(PreAuthTx::from_payload(&payload)?)),
108 version::HASH_X => Ok(Self::HashX(HashX::from_payload(&payload)?)),
109 version::MUXED_ACCOUNT_ED25519 => Ok(Self::MuxedAccountEd25519(
110 ed25519::MuxedAccount::from_payload(&payload)?,
111 )),
112 version::SIGNED_PAYLOAD_ED25519 => Ok(Self::SignedPayloadEd25519(
113 ed25519::SignedPayload::from_payload(&payload)?,
114 )),
115 version::CONTRACT => Ok(Self::Contract(Contract::from_payload(&payload)?)),
116 version::LIQUIDITY_POOL => {
117 Ok(Self::LiquidityPool(LiquidityPool::from_payload(&payload)?))
118 }
119 version::CLAIMABLE_BALANCE => Ok(Self::ClaimableBalance(
120 ClaimableBalance::from_payload(&payload)?,
121 )),
122 _ => Err(DecodeError::UnsupportedVersion),
123 }
124 }
125}
126
127impl Display for Strkey {
128 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
129 write!(f, "{}", self.to_string())
130 }
131}
132
133impl FromStr for Strkey {
134 type Err = DecodeError;
135
136 fn from_str(s: &str) -> Result<Self, Self::Err> {
137 Strkey::from_string(s)
138 }
139}
140
141#[cfg(feature = "serde-decoded")]
142mod strkey_decoded_serde_impl {
143 use super::*;
144 use crate::decoded_json_format::Decoded;
145 use serde::{
146 de::{self, MapAccess, Visitor},
147 ser::SerializeMap,
148 Deserialize, Deserializer, Serialize, Serializer,
149 };
150
151 impl Serialize for Decoded<&Strkey> {
152 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
153 let mut map = serializer.serialize_map(Some(1))?;
154 match self.0 {
155 Strkey::PublicKeyEd25519(key) => {
156 map.serialize_entry("public_key_ed25519", &Decoded(key))?;
157 }
158 Strkey::PreAuthTx(key) => {
159 map.serialize_entry("pre_auth_tx", &Decoded(key))?;
160 }
161 Strkey::HashX(key) => {
162 map.serialize_entry("hash_x", &Decoded(key))?;
163 }
164 Strkey::MuxedAccountEd25519(key) => {
165 map.serialize_entry("muxed_account_ed25519", &Decoded(key))?;
166 }
167 Strkey::SignedPayloadEd25519(key) => {
168 map.serialize_entry("signed_payload_ed25519", &Decoded(key))?;
169 }
170 Strkey::Contract(key) => {
171 map.serialize_entry("contract", &Decoded(key))?;
172 }
173 Strkey::LiquidityPool(key) => {
174 map.serialize_entry("liquidity_pool", &Decoded(key))?;
175 }
176 Strkey::ClaimableBalance(key) => {
177 map.serialize_entry("claimable_balance", &Decoded(key))?;
178 }
179 }
180 map.end()
181 }
182 }
183
184 impl<'de> Deserialize<'de> for Decoded<Strkey> {
185 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
186 struct StrkeyVisitor;
187
188 impl<'de> Visitor<'de> for StrkeyVisitor {
189 type Value = Decoded<Strkey>;
190
191 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
192 formatter.write_str("a strkey object")
193 }
194
195 fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<Self::Value, M::Error> {
196 let key: alloc::string::String = map
202 .next_key()?
203 .ok_or_else(|| de::Error::custom("expected a variant key"))?;
204
205 let strkey = match key.as_str() {
206 "public_key_ed25519" => {
207 let Decoded(inner) = map.next_value()?;
208 Strkey::PublicKeyEd25519(inner)
209 }
210 "pre_auth_tx" => {
211 let Decoded(inner) = map.next_value()?;
212 Strkey::PreAuthTx(inner)
213 }
214 "hash_x" => {
215 let Decoded(inner) = map.next_value()?;
216 Strkey::HashX(inner)
217 }
218 "muxed_account_ed25519" => {
219 let Decoded(inner) = map.next_value()?;
220 Strkey::MuxedAccountEd25519(inner)
221 }
222 "signed_payload_ed25519" => {
223 let Decoded(inner) = map.next_value()?;
224 Strkey::SignedPayloadEd25519(inner)
225 }
226 "contract" => {
227 let Decoded(inner) = map.next_value()?;
228 Strkey::Contract(inner)
229 }
230 "liquidity_pool" => {
231 let Decoded(inner) = map.next_value()?;
232 Strkey::LiquidityPool(inner)
233 }
234 "claimable_balance" => {
235 let Decoded(inner) = map.next_value()?;
236 Strkey::ClaimableBalance(inner)
237 }
238 _ => {
239 return Err(de::Error::unknown_variant(
240 &key,
241 &[
242 "public_key_ed25519",
243 "pre_auth_tx",
244 "hash_x",
245 "muxed_account_ed25519",
246 "signed_payload_ed25519",
247 "contract",
248 "liquidity_pool",
249 "claimable_balance",
250 ],
251 ))
252 }
253 };
254
255 if map.next_key::<de::IgnoredAny>()?.is_some() {
256 return Err(de::Error::custom("expected exactly one variant key"));
257 }
258
259 Ok(Decoded(strkey))
260 }
261 }
262
263 deserializer.deserialize_map(StrkeyVisitor)
264 }
265 }
266}
267
268#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
270#[cfg_attr(
271 feature = "serde",
272 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
273)]
274pub struct PreAuthTx(pub [u8; 32]);
275
276impl Debug for PreAuthTx {
277 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
278 write!(f, "PreAuthTx(")?;
279 for b in &self.0 {
280 write!(f, "{b:02x}")?;
281 }
282 write!(f, ")")
283 }
284}
285
286impl PreAuthTx {
287 pub(crate) const PAYLOAD_LEN: usize = 32;
288 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
289 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
290 const _ASSERTS: () = {
291 assert!(Self::BINARY_LEN == 35);
292 assert!(Self::ENCODED_LEN == 56);
293 };
294
295 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
296 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
297 version::PRE_AUTH_TX,
298 &self.0,
299 )
300 }
301
302 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
303 Ok(Self(
304 payload
305 .try_into()
306 .map_err(|_| DecodeError::InvalidPayloadLength)?,
307 ))
308 }
309
310 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
311 Self::from_slice(s.as_bytes())
312 }
313
314 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
315 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
316 match ver {
317 version::PRE_AUTH_TX => Self::from_payload(&payload),
318 _ => Err(DecodeError::UnsupportedVersion),
319 }
320 }
321}
322
323impl Display for PreAuthTx {
324 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325 write!(f, "{}", self.to_string())
326 }
327}
328
329impl FromStr for PreAuthTx {
330 type Err = DecodeError;
331
332 fn from_str(s: &str) -> Result<Self, Self::Err> {
333 PreAuthTx::from_string(s)
334 }
335}
336
337#[cfg(feature = "serde-decoded")]
338mod pre_auth_tx_decoded_serde_impl {
339 use super::*;
340 use crate::decoded_json_format::Decoded;
341 use serde::{Deserialize, Deserializer, Serialize, Serializer};
342 use serde_with::serde_as;
343
344 #[serde_as]
345 #[derive(Serialize)]
346 #[serde(transparent)]
347 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
348
349 #[serde_as]
350 #[derive(Deserialize)]
351 #[serde(transparent)]
352 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
353
354 impl Serialize for Decoded<&PreAuthTx> {
355 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
356 let Self(PreAuthTx(bytes)) = self;
357 DecodedBorrowed(bytes).serialize(serializer)
358 }
359 }
360
361 impl<'de> Deserialize<'de> for Decoded<PreAuthTx> {
362 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
363 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
364 Ok(Decoded(PreAuthTx(bytes)))
365 }
366 }
367}
368
369#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
371#[cfg_attr(
372 feature = "serde",
373 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
374)]
375pub struct HashX(pub [u8; 32]);
376
377impl Debug for HashX {
378 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
379 write!(f, "HashX(")?;
380 for b in &self.0 {
381 write!(f, "{b:02x}")?;
382 }
383 write!(f, ")")
384 }
385}
386
387impl HashX {
388 pub(crate) const PAYLOAD_LEN: usize = 32;
389 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
390 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
391 const _ASSERTS: () = {
392 assert!(Self::BINARY_LEN == 35);
393 assert!(Self::ENCODED_LEN == 56);
394 };
395
396 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
397 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
398 version::HASH_X,
399 &self.0,
400 )
401 }
402
403 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
404 Ok(Self(
405 payload
406 .try_into()
407 .map_err(|_| DecodeError::InvalidPayloadLength)?,
408 ))
409 }
410
411 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
412 Self::from_slice(s.as_bytes())
413 }
414
415 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
416 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
417 match ver {
418 version::HASH_X => Self::from_payload(&payload),
419 _ => Err(DecodeError::UnsupportedVersion),
420 }
421 }
422}
423
424impl Display for HashX {
425 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
426 write!(f, "{}", self.to_string())
427 }
428}
429
430impl FromStr for HashX {
431 type Err = DecodeError;
432
433 fn from_str(s: &str) -> Result<Self, Self::Err> {
434 HashX::from_string(s)
435 }
436}
437
438#[cfg(feature = "serde-decoded")]
439mod hash_x_decoded_serde_impl {
440 use super::*;
441 use crate::decoded_json_format::Decoded;
442 use serde::{Deserialize, Deserializer, Serialize, Serializer};
443 use serde_with::serde_as;
444
445 #[serde_as]
446 #[derive(Serialize)]
447 #[serde(transparent)]
448 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
449
450 #[serde_as]
451 #[derive(Deserialize)]
452 #[serde(transparent)]
453 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
454
455 impl Serialize for Decoded<&HashX> {
456 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
457 let Self(HashX(bytes)) = self;
458 DecodedBorrowed(bytes).serialize(serializer)
459 }
460 }
461
462 impl<'de> Deserialize<'de> for Decoded<HashX> {
463 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
464 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
465 Ok(Decoded(HashX(bytes)))
466 }
467 }
468}
469
470#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
472#[cfg_attr(
473 feature = "serde",
474 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
475)]
476pub struct Contract(pub [u8; 32]);
477
478impl Debug for Contract {
479 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
480 write!(f, "Contract(")?;
481 for b in &self.0 {
482 write!(f, "{b:02x}")?;
483 }
484 write!(f, ")")
485 }
486}
487
488impl Contract {
489 pub(crate) const PAYLOAD_LEN: usize = 32;
490 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
491 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
492 const _ASSERTS: () = {
493 assert!(Self::BINARY_LEN == 35);
494 assert!(Self::ENCODED_LEN == 56);
495 };
496
497 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
498 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
499 version::CONTRACT,
500 &self.0,
501 )
502 }
503
504 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
505 Ok(Self(
506 payload
507 .try_into()
508 .map_err(|_| DecodeError::InvalidPayloadLength)?,
509 ))
510 }
511
512 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
513 Self::from_slice(s.as_bytes())
514 }
515
516 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
517 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
518 match ver {
519 version::CONTRACT => Self::from_payload(&payload),
520 _ => Err(DecodeError::UnsupportedVersion),
521 }
522 }
523}
524
525impl Display for Contract {
526 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
527 write!(f, "{}", self.to_string())
528 }
529}
530
531impl FromStr for Contract {
532 type Err = DecodeError;
533
534 fn from_str(s: &str) -> Result<Self, Self::Err> {
535 Contract::from_string(s)
536 }
537}
538
539#[cfg(feature = "serde-decoded")]
540mod contract_decoded_serde_impl {
541 use super::*;
542 use crate::decoded_json_format::Decoded;
543 use serde::{Deserialize, Deserializer, Serialize, Serializer};
544 use serde_with::serde_as;
545
546 #[serde_as]
547 #[derive(Serialize)]
548 #[serde(transparent)]
549 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
550
551 #[serde_as]
552 #[derive(Deserialize)]
553 #[serde(transparent)]
554 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
555
556 impl Serialize for Decoded<&Contract> {
557 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
558 let Self(Contract(bytes)) = self;
559 DecodedBorrowed(bytes).serialize(serializer)
560 }
561 }
562
563 impl<'de> Deserialize<'de> for Decoded<Contract> {
564 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
565 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
566 Ok(Decoded(Contract(bytes)))
567 }
568 }
569}
570
571#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
573#[cfg_attr(
574 feature = "serde",
575 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
576)]
577pub struct LiquidityPool(pub [u8; 32]);
578
579impl Debug for LiquidityPool {
580 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
581 write!(f, "LiquidityPool(")?;
582 for b in &self.0 {
583 write!(f, "{b:02x}")?;
584 }
585 write!(f, ")")
586 }
587}
588
589impl LiquidityPool {
590 pub(crate) const PAYLOAD_LEN: usize = 32;
591 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
592 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
593 const _ASSERTS: () = {
594 assert!(Self::BINARY_LEN == 35);
595 assert!(Self::ENCODED_LEN == 56);
596 };
597
598 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
599 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
600 version::LIQUIDITY_POOL,
601 &self.0,
602 )
603 }
604
605 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
606 Ok(Self(
607 payload
608 .try_into()
609 .map_err(|_| DecodeError::InvalidPayloadLength)?,
610 ))
611 }
612
613 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
614 Self::from_slice(s.as_bytes())
615 }
616
617 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
618 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
619 match ver {
620 version::LIQUIDITY_POOL => Self::from_payload(&payload),
621 _ => Err(DecodeError::UnsupportedVersion),
622 }
623 }
624}
625
626impl Display for LiquidityPool {
627 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
628 write!(f, "{}", self.to_string())
629 }
630}
631
632impl FromStr for LiquidityPool {
633 type Err = DecodeError;
634
635 fn from_str(s: &str) -> Result<Self, Self::Err> {
636 LiquidityPool::from_string(s)
637 }
638}
639
640#[cfg(feature = "serde-decoded")]
641mod liquidity_pool_decoded_serde_impl {
642 use super::*;
643 use crate::decoded_json_format::Decoded;
644 use serde::{Deserialize, Deserializer, Serialize, Serializer};
645 use serde_with::serde_as;
646
647 #[serde_as]
648 #[derive(Serialize)]
649 #[serde(transparent)]
650 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
651
652 #[serde_as]
653 #[derive(Deserialize)]
654 #[serde(transparent)]
655 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
656
657 impl Serialize for Decoded<&LiquidityPool> {
658 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
659 let Self(LiquidityPool(bytes)) = self;
660 DecodedBorrowed(bytes).serialize(serializer)
661 }
662 }
663
664 impl<'de> Deserialize<'de> for Decoded<LiquidityPool> {
665 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
666 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
667 Ok(Decoded(LiquidityPool(bytes)))
668 }
669 }
670}
671
672#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
674#[cfg_attr(
675 feature = "serde",
676 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
677)]
678pub enum ClaimableBalance {
679 V0([u8; 32]),
680}
681
682impl Debug for ClaimableBalance {
683 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
684 write!(f, "ClaimableBalance(")?;
685 match self {
686 Self::V0(v0) => {
687 write!(f, "V0(")?;
688 for b in v0 {
689 write!(f, "{b:02x}")?;
690 }
691 write!(f, ")")?;
692 }
693 }
694 write!(f, ")")
695 }
696}
697
698impl ClaimableBalance {
699 pub(crate) const PAYLOAD_LEN: usize = 1 + 32;
701 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
702 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
703 const _ASSERTS: () = {
704 assert!(Self::PAYLOAD_LEN == 33);
705 assert!(Self::BINARY_LEN == 36);
706 assert!(Self::ENCODED_LEN == 58);
707 };
708
709 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
710 match self {
711 Self::V0(v0) => {
712 let mut payload = [0; Self::PAYLOAD_LEN];
714 payload[1..].copy_from_slice(v0);
715 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
716 version::CLAIMABLE_BALANCE,
717 &payload,
718 )
719 }
720 }
721 }
722
723 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
724 match payload {
725 [0, rest @ ..] => Ok(Self::V0(
727 rest.try_into()
728 .map_err(|_| DecodeError::InvalidPayloadLength)?,
729 )),
730 [_, ..] => Err(DecodeError::UnsupportedClaimableBalanceVersion),
731 [] => Err(DecodeError::InvalidPayloadLength),
732 }
733 }
734
735 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
736 Self::from_slice(s.as_bytes())
737 }
738
739 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
740 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
741 match ver {
742 version::CLAIMABLE_BALANCE => Self::from_payload(&payload),
743 _ => Err(DecodeError::UnsupportedVersion),
744 }
745 }
746}
747
748impl Display for ClaimableBalance {
749 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
750 write!(f, "{}", self.to_string())
751 }
752}
753
754impl FromStr for ClaimableBalance {
755 type Err = DecodeError;
756
757 fn from_str(s: &str) -> Result<Self, Self::Err> {
758 ClaimableBalance::from_string(s)
759 }
760}
761
762#[cfg(feature = "serde-decoded")]
763mod claimable_balance_decoded_serde_impl {
764 use super::*;
765 use crate::decoded_json_format::Decoded;
766 use serde::{Deserialize, Deserializer, Serialize, Serializer};
767 use serde_with::serde_as;
768
769 #[serde_as]
770 #[derive(Serialize)]
771 #[serde(rename_all = "snake_case")]
772 enum DecodedBorrowed<'a> {
773 V0(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]),
774 }
775
776 #[serde_as]
777 #[derive(Deserialize)]
778 #[serde(rename_all = "snake_case")]
779 enum DecodedOwned {
780 V0(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]),
781 }
782
783 impl Serialize for Decoded<&ClaimableBalance> {
784 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
785 match self.0 {
786 ClaimableBalance::V0(bytes) => DecodedBorrowed::V0(bytes).serialize(serializer),
787 }
788 }
789 }
790
791 impl<'de> Deserialize<'de> for Decoded<ClaimableBalance> {
792 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
793 let decoded = DecodedOwned::deserialize(deserializer)?;
794 Ok(Decoded(match decoded {
795 DecodedOwned::V0(bytes) => ClaimableBalance::V0(bytes),
796 }))
797 }
798 }
799}