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: &str = map
197 .next_key()?
198 .ok_or_else(|| de::Error::custom("expected a variant key"))?;
199
200 let strkey = match key {
201 "public_key_ed25519" => {
202 let Decoded(inner) = map.next_value()?;
203 Strkey::PublicKeyEd25519(inner)
204 }
205 "pre_auth_tx" => {
206 let Decoded(inner) = map.next_value()?;
207 Strkey::PreAuthTx(inner)
208 }
209 "hash_x" => {
210 let Decoded(inner) = map.next_value()?;
211 Strkey::HashX(inner)
212 }
213 "muxed_account_ed25519" => {
214 let Decoded(inner) = map.next_value()?;
215 Strkey::MuxedAccountEd25519(inner)
216 }
217 "signed_payload_ed25519" => {
218 let Decoded(inner) = map.next_value()?;
219 Strkey::SignedPayloadEd25519(inner)
220 }
221 "contract" => {
222 let Decoded(inner) = map.next_value()?;
223 Strkey::Contract(inner)
224 }
225 "liquidity_pool" => {
226 let Decoded(inner) = map.next_value()?;
227 Strkey::LiquidityPool(inner)
228 }
229 "claimable_balance" => {
230 let Decoded(inner) = map.next_value()?;
231 Strkey::ClaimableBalance(inner)
232 }
233 _ => {
234 return Err(de::Error::unknown_variant(
235 key,
236 &[
237 "public_key_ed25519",
238 "pre_auth_tx",
239 "hash_x",
240 "muxed_account_ed25519",
241 "signed_payload_ed25519",
242 "contract",
243 "liquidity_pool",
244 "claimable_balance",
245 ],
246 ))
247 }
248 };
249
250 if map.next_key::<de::IgnoredAny>()?.is_some() {
251 return Err(de::Error::custom("expected exactly one variant key"));
252 }
253
254 Ok(Decoded(strkey))
255 }
256 }
257
258 deserializer.deserialize_map(StrkeyVisitor)
259 }
260 }
261}
262
263#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
265#[cfg_attr(
266 feature = "serde",
267 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
268)]
269pub struct PreAuthTx(pub [u8; 32]);
270
271impl Debug for PreAuthTx {
272 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
273 write!(f, "PreAuthTx(")?;
274 for b in &self.0 {
275 write!(f, "{b:02x}")?;
276 }
277 write!(f, ")")
278 }
279}
280
281impl PreAuthTx {
282 pub(crate) const PAYLOAD_LEN: usize = 32;
283 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
284 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
285 const _ASSERTS: () = {
286 assert!(Self::BINARY_LEN == 35);
287 assert!(Self::ENCODED_LEN == 56);
288 };
289
290 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
291 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
292 version::PRE_AUTH_TX,
293 &self.0,
294 )
295 }
296
297 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
298 Ok(Self(
299 payload
300 .try_into()
301 .map_err(|_| DecodeError::InvalidPayloadLength)?,
302 ))
303 }
304
305 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
306 Self::from_slice(s.as_bytes())
307 }
308
309 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
310 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
311 match ver {
312 version::PRE_AUTH_TX => Self::from_payload(&payload),
313 _ => Err(DecodeError::UnsupportedVersion),
314 }
315 }
316}
317
318impl Display for PreAuthTx {
319 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
320 write!(f, "{}", self.to_string())
321 }
322}
323
324impl FromStr for PreAuthTx {
325 type Err = DecodeError;
326
327 fn from_str(s: &str) -> Result<Self, Self::Err> {
328 PreAuthTx::from_string(s)
329 }
330}
331
332#[cfg(feature = "serde-decoded")]
333mod pre_auth_tx_decoded_serde_impl {
334 use super::*;
335 use crate::decoded_json_format::Decoded;
336 use serde::{Deserialize, Deserializer, Serialize, Serializer};
337 use serde_with::serde_as;
338
339 #[serde_as]
340 #[derive(Serialize)]
341 #[serde(transparent)]
342 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
343
344 #[serde_as]
345 #[derive(Deserialize)]
346 #[serde(transparent)]
347 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
348
349 impl Serialize for Decoded<&PreAuthTx> {
350 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
351 let Self(PreAuthTx(bytes)) = self;
352 DecodedBorrowed(bytes).serialize(serializer)
353 }
354 }
355
356 impl<'de> Deserialize<'de> for Decoded<PreAuthTx> {
357 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
358 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
359 Ok(Decoded(PreAuthTx(bytes)))
360 }
361 }
362}
363
364#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
366#[cfg_attr(
367 feature = "serde",
368 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
369)]
370pub struct HashX(pub [u8; 32]);
371
372impl Debug for HashX {
373 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
374 write!(f, "HashX(")?;
375 for b in &self.0 {
376 write!(f, "{b:02x}")?;
377 }
378 write!(f, ")")
379 }
380}
381
382impl HashX {
383 pub(crate) const PAYLOAD_LEN: usize = 32;
384 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
385 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
386 const _ASSERTS: () = {
387 assert!(Self::BINARY_LEN == 35);
388 assert!(Self::ENCODED_LEN == 56);
389 };
390
391 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
392 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
393 version::HASH_X,
394 &self.0,
395 )
396 }
397
398 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
399 Ok(Self(
400 payload
401 .try_into()
402 .map_err(|_| DecodeError::InvalidPayloadLength)?,
403 ))
404 }
405
406 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
407 Self::from_slice(s.as_bytes())
408 }
409
410 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
411 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
412 match ver {
413 version::HASH_X => Self::from_payload(&payload),
414 _ => Err(DecodeError::UnsupportedVersion),
415 }
416 }
417}
418
419impl Display for HashX {
420 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
421 write!(f, "{}", self.to_string())
422 }
423}
424
425impl FromStr for HashX {
426 type Err = DecodeError;
427
428 fn from_str(s: &str) -> Result<Self, Self::Err> {
429 HashX::from_string(s)
430 }
431}
432
433#[cfg(feature = "serde-decoded")]
434mod hash_x_decoded_serde_impl {
435 use super::*;
436 use crate::decoded_json_format::Decoded;
437 use serde::{Deserialize, Deserializer, Serialize, Serializer};
438 use serde_with::serde_as;
439
440 #[serde_as]
441 #[derive(Serialize)]
442 #[serde(transparent)]
443 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
444
445 #[serde_as]
446 #[derive(Deserialize)]
447 #[serde(transparent)]
448 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
449
450 impl Serialize for Decoded<&HashX> {
451 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
452 let Self(HashX(bytes)) = self;
453 DecodedBorrowed(bytes).serialize(serializer)
454 }
455 }
456
457 impl<'de> Deserialize<'de> for Decoded<HashX> {
458 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
459 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
460 Ok(Decoded(HashX(bytes)))
461 }
462 }
463}
464
465#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
467#[cfg_attr(
468 feature = "serde",
469 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
470)]
471pub struct Contract(pub [u8; 32]);
472
473impl Debug for Contract {
474 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
475 write!(f, "Contract(")?;
476 for b in &self.0 {
477 write!(f, "{b:02x}")?;
478 }
479 write!(f, ")")
480 }
481}
482
483impl Contract {
484 pub(crate) const PAYLOAD_LEN: usize = 32;
485 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
486 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
487 const _ASSERTS: () = {
488 assert!(Self::BINARY_LEN == 35);
489 assert!(Self::ENCODED_LEN == 56);
490 };
491
492 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
493 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
494 version::CONTRACT,
495 &self.0,
496 )
497 }
498
499 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
500 Ok(Self(
501 payload
502 .try_into()
503 .map_err(|_| DecodeError::InvalidPayloadLength)?,
504 ))
505 }
506
507 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
508 Self::from_slice(s.as_bytes())
509 }
510
511 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
512 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
513 match ver {
514 version::CONTRACT => Self::from_payload(&payload),
515 _ => Err(DecodeError::UnsupportedVersion),
516 }
517 }
518}
519
520impl Display for Contract {
521 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
522 write!(f, "{}", self.to_string())
523 }
524}
525
526impl FromStr for Contract {
527 type Err = DecodeError;
528
529 fn from_str(s: &str) -> Result<Self, Self::Err> {
530 Contract::from_string(s)
531 }
532}
533
534#[cfg(feature = "serde-decoded")]
535mod contract_decoded_serde_impl {
536 use super::*;
537 use crate::decoded_json_format::Decoded;
538 use serde::{Deserialize, Deserializer, Serialize, Serializer};
539 use serde_with::serde_as;
540
541 #[serde_as]
542 #[derive(Serialize)]
543 #[serde(transparent)]
544 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
545
546 #[serde_as]
547 #[derive(Deserialize)]
548 #[serde(transparent)]
549 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
550
551 impl Serialize for Decoded<&Contract> {
552 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
553 let Self(Contract(bytes)) = self;
554 DecodedBorrowed(bytes).serialize(serializer)
555 }
556 }
557
558 impl<'de> Deserialize<'de> for Decoded<Contract> {
559 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
560 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
561 Ok(Decoded(Contract(bytes)))
562 }
563 }
564}
565
566#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
568#[cfg_attr(
569 feature = "serde",
570 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
571)]
572pub struct LiquidityPool(pub [u8; 32]);
573
574impl Debug for LiquidityPool {
575 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
576 write!(f, "LiquidityPool(")?;
577 for b in &self.0 {
578 write!(f, "{b:02x}")?;
579 }
580 write!(f, ")")
581 }
582}
583
584impl LiquidityPool {
585 pub(crate) const PAYLOAD_LEN: usize = 32;
586 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
587 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
588 const _ASSERTS: () = {
589 assert!(Self::BINARY_LEN == 35);
590 assert!(Self::ENCODED_LEN == 56);
591 };
592
593 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
594 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
595 version::LIQUIDITY_POOL,
596 &self.0,
597 )
598 }
599
600 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
601 Ok(Self(
602 payload
603 .try_into()
604 .map_err(|_| DecodeError::InvalidPayloadLength)?,
605 ))
606 }
607
608 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
609 Self::from_slice(s.as_bytes())
610 }
611
612 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
613 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
614 match ver {
615 version::LIQUIDITY_POOL => Self::from_payload(&payload),
616 _ => Err(DecodeError::UnsupportedVersion),
617 }
618 }
619}
620
621impl Display for LiquidityPool {
622 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
623 write!(f, "{}", self.to_string())
624 }
625}
626
627impl FromStr for LiquidityPool {
628 type Err = DecodeError;
629
630 fn from_str(s: &str) -> Result<Self, Self::Err> {
631 LiquidityPool::from_string(s)
632 }
633}
634
635#[cfg(feature = "serde-decoded")]
636mod liquidity_pool_decoded_serde_impl {
637 use super::*;
638 use crate::decoded_json_format::Decoded;
639 use serde::{Deserialize, Deserializer, Serialize, Serializer};
640 use serde_with::serde_as;
641
642 #[serde_as]
643 #[derive(Serialize)]
644 #[serde(transparent)]
645 struct DecodedBorrowed<'a>(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]);
646
647 #[serde_as]
648 #[derive(Deserialize)]
649 #[serde(transparent)]
650 struct DecodedOwned(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]);
651
652 impl Serialize for Decoded<&LiquidityPool> {
653 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
654 let Self(LiquidityPool(bytes)) = self;
655 DecodedBorrowed(bytes).serialize(serializer)
656 }
657 }
658
659 impl<'de> Deserialize<'de> for Decoded<LiquidityPool> {
660 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
661 let DecodedOwned(bytes) = DecodedOwned::deserialize(deserializer)?;
662 Ok(Decoded(LiquidityPool(bytes)))
663 }
664 }
665}
666
667#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
669#[cfg_attr(
670 feature = "serde",
671 derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr)
672)]
673pub enum ClaimableBalance {
674 V0([u8; 32]),
675}
676
677impl Debug for ClaimableBalance {
678 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
679 write!(f, "ClaimableBalance(")?;
680 match self {
681 Self::V0(v0) => {
682 write!(f, "V0(")?;
683 for b in v0 {
684 write!(f, "{b:02x}")?;
685 }
686 write!(f, ")")?;
687 }
688 }
689 write!(f, ")")
690 }
691}
692
693impl ClaimableBalance {
694 pub(crate) const PAYLOAD_LEN: usize = 1 + 32;
696 pub(crate) const BINARY_LEN: usize = binary_len(Self::PAYLOAD_LEN);
697 pub const ENCODED_LEN: usize = encode_len(Self::BINARY_LEN);
698 const _ASSERTS: () = {
699 assert!(Self::PAYLOAD_LEN == 33);
700 assert!(Self::BINARY_LEN == 36);
701 assert!(Self::ENCODED_LEN == 58);
702 };
703
704 pub fn to_string(&self) -> HeaplessString<{ Self::ENCODED_LEN }> {
705 match self {
706 Self::V0(v0) => {
707 let mut payload = [0; Self::PAYLOAD_LEN];
709 payload[1..].copy_from_slice(v0);
710 encode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }, { Self::ENCODED_LEN }>(
711 version::CLAIMABLE_BALANCE,
712 &payload,
713 )
714 }
715 }
716 }
717
718 fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
719 match payload {
720 [0, rest @ ..] => Ok(Self::V0(
722 rest.try_into()
723 .map_err(|_| DecodeError::InvalidPayloadLength)?,
724 )),
725 [_, ..] => Err(DecodeError::UnsupportedClaimableBalanceVersion),
726 [] => Err(DecodeError::InvalidPayloadLength),
727 }
728 }
729
730 pub fn from_string(s: &str) -> Result<Self, DecodeError> {
731 Self::from_slice(s.as_bytes())
732 }
733
734 pub fn from_slice(s: &[u8]) -> Result<Self, DecodeError> {
735 let (ver, payload) = decode::<{ Self::PAYLOAD_LEN }, { Self::BINARY_LEN }>(s)?;
736 match ver {
737 version::CLAIMABLE_BALANCE => Self::from_payload(&payload),
738 _ => Err(DecodeError::UnsupportedVersion),
739 }
740 }
741}
742
743impl Display for ClaimableBalance {
744 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
745 write!(f, "{}", self.to_string())
746 }
747}
748
749impl FromStr for ClaimableBalance {
750 type Err = DecodeError;
751
752 fn from_str(s: &str) -> Result<Self, Self::Err> {
753 ClaimableBalance::from_string(s)
754 }
755}
756
757#[cfg(feature = "serde-decoded")]
758mod claimable_balance_decoded_serde_impl {
759 use super::*;
760 use crate::decoded_json_format::Decoded;
761 use serde::{Deserialize, Deserializer, Serialize, Serializer};
762 use serde_with::serde_as;
763
764 #[serde_as]
765 #[derive(Serialize)]
766 #[serde(rename_all = "snake_case")]
767 enum DecodedBorrowed<'a> {
768 V0(#[serde_as(as = "serde_with::hex::Hex")] &'a [u8; 32]),
769 }
770
771 #[serde_as]
772 #[derive(Deserialize)]
773 #[serde(rename_all = "snake_case")]
774 enum DecodedOwned {
775 V0(#[serde_as(as = "serde_with::hex::Hex")] [u8; 32]),
776 }
777
778 impl Serialize for Decoded<&ClaimableBalance> {
779 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
780 match self.0 {
781 ClaimableBalance::V0(bytes) => DecodedBorrowed::V0(bytes).serialize(serializer),
782 }
783 }
784 }
785
786 impl<'de> Deserialize<'de> for Decoded<ClaimableBalance> {
787 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
788 let decoded = DecodedOwned::deserialize(deserializer)?;
789 Ok(Decoded(match decoded {
790 DecodedOwned::V0(bytes) => ClaimableBalance::V0(bytes),
791 }))
792 }
793 }
794}