1use alloc::{string::String, vec::Vec};
2use core::fmt::{self, Display, Formatter};
3#[cfg(feature = "datasize")]
4use datasize::DataSize;
5#[cfg(feature = "json-schema")]
6use schemars::JsonSchema;
7
8use super::{BidAddr, DelegatorKind, UnbondingPurse, WithdrawPurse};
9use crate::{
10 bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
11 checksummed_hex, CLType, CLTyped, EraId, PublicKey, URef, URefAddr, U512,
12};
13use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
14use serde_helpers::{HumanReadableUnbondKind, NonHumanReadableUnbondKind};
15
16#[allow(clippy::large_enum_variant)]
18#[repr(u8)]
19#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
20pub enum UnbondKindTag {
21 Validator = 0,
23 DelegatedAccount = 1,
25 DelegatedPurse = 2,
27}
28
29#[derive(Debug, PartialEq, Eq, Clone, Ord, PartialOrd)]
31#[cfg_attr(feature = "datasize", derive(DataSize))]
32#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
33pub enum UnbondKind {
34 Validator(PublicKey),
35 DelegatedPublicKey(PublicKey),
36 DelegatedPurse(#[cfg_attr(feature = "json-schema", schemars(with = "String"))] URefAddr),
37}
38
39impl UnbondKind {
40 pub fn tag(&self) -> UnbondKindTag {
42 match self {
43 UnbondKind::Validator(_) => UnbondKindTag::Validator,
44 UnbondKind::DelegatedPublicKey(_) => UnbondKindTag::DelegatedAccount,
45 UnbondKind::DelegatedPurse(_) => UnbondKindTag::DelegatedPurse,
46 }
47 }
48
49 pub fn maybe_public_key(&self) -> Option<PublicKey> {
51 match self {
52 UnbondKind::Validator(pk) | UnbondKind::DelegatedPublicKey(pk) => Some(pk.clone()),
53 UnbondKind::DelegatedPurse(_) => None,
54 }
55 }
56
57 pub fn is_validator(&self) -> bool {
59 match self {
60 UnbondKind::Validator(_) => true,
61 UnbondKind::DelegatedPublicKey(_) | UnbondKind::DelegatedPurse(_) => false,
62 }
63 }
64
65 pub fn is_delegator(&self) -> bool {
67 !self.is_validator()
68 }
69
70 pub fn bid_addr(&self, validator_public_key: &PublicKey) -> BidAddr {
72 match self {
73 UnbondKind::Validator(pk) => BidAddr::UnbondAccount {
74 validator: validator_public_key.to_account_hash(),
75 unbonder: pk.to_account_hash(),
76 },
77 UnbondKind::DelegatedPublicKey(pk) => BidAddr::DelegatedAccount {
78 delegator: pk.to_account_hash(),
79 validator: validator_public_key.to_account_hash(),
80 },
81 UnbondKind::DelegatedPurse(addr) => BidAddr::DelegatedPurse {
82 validator: validator_public_key.to_account_hash(),
83 delegator: *addr,
84 },
85 }
86 }
87}
88
89impl ToBytes for UnbondKind {
90 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
91 let mut result = bytesrepr::allocate_buffer(self)?;
92 let (tag, mut serialized_data) = match self {
93 UnbondKind::Validator(pk) => (UnbondKindTag::Validator, pk.to_bytes()?),
94 UnbondKind::DelegatedPublicKey(pk) => (UnbondKindTag::DelegatedAccount, pk.to_bytes()?),
95 UnbondKind::DelegatedPurse(addr) => (UnbondKindTag::DelegatedPurse, addr.to_bytes()?),
96 };
97 result.push(tag as u8);
98 result.append(&mut serialized_data);
99 Ok(result)
100 }
101
102 fn serialized_length(&self) -> usize {
103 U8_SERIALIZED_LENGTH
104 + match self {
105 UnbondKind::Validator(pk) => pk.serialized_length(),
106 UnbondKind::DelegatedPublicKey(pk) => pk.serialized_length(),
107 UnbondKind::DelegatedPurse(addr) => addr.serialized_length(),
108 }
109 }
110
111 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
112 writer.push(self.tag() as u8);
113 match self {
114 UnbondKind::Validator(pk) => pk.write_bytes(writer)?,
115 UnbondKind::DelegatedPublicKey(pk) => pk.write_bytes(writer)?,
116 UnbondKind::DelegatedPurse(addr) => addr.write_bytes(writer)?,
117 };
118 Ok(())
119 }
120}
121
122impl FromBytes for UnbondKind {
123 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
124 let (tag, remainder): (u8, &[u8]) = FromBytes::from_bytes(bytes)?;
125 match tag {
126 tag if tag == UnbondKindTag::Validator as u8 => PublicKey::from_bytes(remainder)
127 .map(|(pk, remainder)| (UnbondKind::Validator(pk), remainder)),
128 tag if tag == UnbondKindTag::DelegatedAccount as u8 => PublicKey::from_bytes(remainder)
129 .map(|(pk, remainder)| (UnbondKind::DelegatedPublicKey(pk), remainder)),
130 tag if tag == UnbondKindTag::DelegatedPurse as u8 => URefAddr::from_bytes(remainder)
131 .map(|(delegator_bid, remainder)| {
132 (UnbondKind::DelegatedPurse(delegator_bid), remainder)
133 }),
134 _ => Err(bytesrepr::Error::Formatting),
135 }
136 }
137}
138
139impl From<DelegatorKind> for UnbondKind {
140 fn from(value: DelegatorKind) -> Self {
141 match value {
142 DelegatorKind::PublicKey(pk) => UnbondKind::DelegatedPublicKey(pk),
143 DelegatorKind::Purse(addr) => UnbondKind::DelegatedPurse(addr),
144 }
145 }
146}
147
148impl Serialize for UnbondKind {
149 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
150 if serializer.is_human_readable() {
151 HumanReadableUnbondKind::from(self).serialize(serializer)
152 } else {
153 NonHumanReadableUnbondKind::from(self).serialize(serializer)
154 }
155 }
156}
157
158#[derive(Debug)]
159enum UnbondKindError {
160 DeserializationError(String),
161}
162
163impl Display for UnbondKindError {
164 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
165 match self {
166 UnbondKindError::DeserializationError(msg) => {
167 write!(f, "Error when deserializing UnbondKind: {}", msg)
168 }
169 }
170 }
171}
172
173impl TryFrom<HumanReadableUnbondKind> for UnbondKind {
174 type Error = UnbondKindError;
175
176 fn try_from(value: HumanReadableUnbondKind) -> Result<Self, Self::Error> {
177 match value {
178 HumanReadableUnbondKind::Validator(public_key) => Ok(UnbondKind::Validator(public_key)),
179 HumanReadableUnbondKind::DelegatedPublicKey(public_key) => {
180 Ok(UnbondKind::DelegatedPublicKey(public_key))
181 }
182 HumanReadableUnbondKind::DelegatedPurse(encoded) => {
183 let decoded = checksummed_hex::decode(encoded).map_err(|e| {
184 UnbondKindError::DeserializationError(format!(
185 "Failed to decode encoded URefAddr: {}",
186 e
187 ))
188 })?;
189 let uref_addr = URefAddr::try_from(decoded.as_ref()).map_err(|e| {
190 UnbondKindError::DeserializationError(format!(
191 "Failed to build uref address: {}",
192 e
193 ))
194 })?;
195 Ok(UnbondKind::DelegatedPurse(uref_addr))
196 }
197 }
198 }
199}
200
201impl From<NonHumanReadableUnbondKind> for UnbondKind {
202 fn from(value: NonHumanReadableUnbondKind) -> Self {
203 match value {
204 NonHumanReadableUnbondKind::Validator(public_key) => UnbondKind::Validator(public_key),
205 NonHumanReadableUnbondKind::DelegatedPublicKey(public_key) => {
206 UnbondKind::DelegatedPublicKey(public_key)
207 }
208 NonHumanReadableUnbondKind::DelegatedPurse(uref_addr) => {
209 UnbondKind::DelegatedPurse(uref_addr)
210 }
211 }
212 }
213}
214
215impl<'de> Deserialize<'de> for UnbondKind {
216 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
217 if deserializer.is_human_readable() {
218 let human_readable = HumanReadableUnbondKind::deserialize(deserializer)?;
219 UnbondKind::try_from(human_readable)
220 .map_err(|error| SerdeError::custom(format!("{:?}", error)))
221 } else {
222 let non_human_readable = NonHumanReadableUnbondKind::deserialize(deserializer)?;
223 Ok(UnbondKind::from(non_human_readable))
224 }
225 }
226}
227
228#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
229#[cfg_attr(feature = "datasize", derive(DataSize))]
230#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
231#[serde(deny_unknown_fields)]
232pub struct Unbond {
233 validator_public_key: PublicKey,
235 unbond_kind: UnbondKind,
237 eras: Vec<UnbondEra>,
239}
240
241impl Unbond {
242 pub const fn new(
244 validator_public_key: PublicKey,
245 unbond_kind: UnbondKind,
246 eras: Vec<UnbondEra>,
247 ) -> Self {
248 Self {
249 validator_public_key,
250 unbond_kind,
251 eras,
252 }
253 }
254
255 pub fn new_validator_unbond(validator_public_key: PublicKey, eras: Vec<UnbondEra>) -> Self {
257 Self {
258 validator_public_key: validator_public_key.clone(),
259 unbond_kind: UnbondKind::Validator(validator_public_key),
260 eras,
261 }
262 }
263
264 pub const fn new_delegated_account_unbond(
266 validator_public_key: PublicKey,
267 delegator_public_key: PublicKey,
268 eras: Vec<UnbondEra>,
269 ) -> Self {
270 Self {
271 validator_public_key,
272 unbond_kind: UnbondKind::DelegatedPublicKey(delegator_public_key),
273 eras,
274 }
275 }
276
277 pub const fn new_delegated_purse_unbond(
279 validator_public_key: PublicKey,
280 delegator_purse_addr: URefAddr,
281 eras: Vec<UnbondEra>,
282 ) -> Self {
283 Self {
284 validator_public_key,
285 unbond_kind: UnbondKind::DelegatedPurse(delegator_purse_addr),
286 eras,
287 }
288 }
289
290 pub fn is_validator(&self) -> bool {
293 match self.unbond_kind.maybe_public_key() {
294 Some(pk) => pk == self.validator_public_key,
295 None => false,
296 }
297 }
298
299 pub fn validator_public_key(&self) -> &PublicKey {
301 &self.validator_public_key
302 }
303
304 pub fn unbond_kind(&self) -> &UnbondKind {
306 &self.unbond_kind
307 }
308
309 pub fn eras(&self) -> &Vec<UnbondEra> {
311 &self.eras
312 }
313
314 pub fn eras_mut(&mut self) -> &mut Vec<UnbondEra> {
316 &mut self.eras
317 }
318
319 pub fn take_eras(mut self) -> Vec<UnbondEra> {
321 let eras = self.eras;
322 self.eras = vec![];
323 eras
324 }
325
326 pub fn expired(self, era_id: EraId, unbonding_delay: u64) -> (Unbond, Option<Vec<UnbondEra>>) {
328 let mut retained = vec![];
329 let mut expired = vec![];
330 for era in self.eras {
331 let threshold = era
332 .era_of_creation()
333 .value()
334 .saturating_add(unbonding_delay);
335 if era_id.value() >= threshold {
336 expired.push(era);
337 } else {
338 retained.push(era)
339 }
340 }
341 let ret = Unbond::new(self.validator_public_key, self.unbond_kind, retained);
342 if !expired.is_empty() {
343 (ret, Some(expired))
344 } else {
345 (ret, None)
346 }
347 }
348
349 pub fn target_unbond_era(&self) -> Option<UnbondEra> {
351 self.eras()
352 .iter()
353 .max_by(|x, y| x.era_of_creation().cmp(&y.era_of_creation()))
354 .cloned()
355 }
356
357 pub fn target_unbond_era_mut(&mut self) -> Option<&mut UnbondEra> {
359 self.eras_mut()
360 .iter_mut()
361 .max_by(|x, y| x.era_of_creation().cmp(&y.era_of_creation()))
362 }
363}
364
365impl ToBytes for Unbond {
366 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
367 let mut result = bytesrepr::allocate_buffer(self)?;
368 result.extend(&self.validator_public_key.to_bytes()?);
369 result.extend(&self.unbond_kind.to_bytes()?);
370 result.extend(&self.eras.to_bytes()?);
371 Ok(result)
372 }
373 fn serialized_length(&self) -> usize {
374 self.validator_public_key.serialized_length()
375 + self.unbond_kind.serialized_length()
376 + self.eras.serialized_length()
377 }
378
379 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
380 self.validator_public_key.write_bytes(writer)?;
381 self.unbond_kind.write_bytes(writer)?;
382 self.eras.write_bytes(writer)?;
383 Ok(())
384 }
385}
386
387impl FromBytes for Unbond {
388 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
389 let (validator_public_key, remainder) = FromBytes::from_bytes(bytes)?;
390 let (unbond_kind, remainder) = FromBytes::from_bytes(remainder)?;
391 let (eras, remainder) = FromBytes::from_bytes(remainder)?;
392
393 Ok((
394 Unbond {
395 validator_public_key,
396 unbond_kind,
397 eras,
398 },
399 remainder,
400 ))
401 }
402}
403
404impl CLTyped for Unbond {
405 fn cl_type() -> CLType {
406 CLType::Any
407 }
408}
409
410impl Default for Unbond {
411 fn default() -> Self {
412 Self {
413 unbond_kind: UnbondKind::Validator(PublicKey::System),
414 validator_public_key: PublicKey::System,
415 eras: vec![],
416 }
417 }
418}
419
420impl From<UnbondingPurse> for Unbond {
421 fn from(unbonding_purse: UnbondingPurse) -> Self {
422 let unbond_kind =
423 if unbonding_purse.validator_public_key() == unbonding_purse.unbonder_public_key() {
424 UnbondKind::Validator(unbonding_purse.validator_public_key().clone())
425 } else {
426 UnbondKind::DelegatedPublicKey(unbonding_purse.unbonder_public_key().clone())
427 };
428 Unbond::new(
429 unbonding_purse.validator_public_key().clone(),
430 unbond_kind,
431 vec![UnbondEra::new(
432 *unbonding_purse.bonding_purse(),
433 unbonding_purse.era_of_creation(),
434 *unbonding_purse.amount(),
435 None,
436 )],
437 )
438 }
439}
440
441impl From<WithdrawPurse> for Unbond {
442 fn from(withdraw_purse: WithdrawPurse) -> Self {
443 let unbond_kind =
444 if withdraw_purse.validator_public_key == withdraw_purse.unbonder_public_key {
445 UnbondKind::Validator(withdraw_purse.validator_public_key.clone())
446 } else {
447 UnbondKind::DelegatedPublicKey(withdraw_purse.unbonder_public_key.clone())
448 };
449 Unbond::new(
450 withdraw_purse.validator_public_key,
451 unbond_kind,
452 vec![UnbondEra::new(
453 withdraw_purse.bonding_purse,
454 withdraw_purse.era_of_creation,
455 withdraw_purse.amount,
456 None,
457 )],
458 )
459 }
460}
461
462#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
464#[cfg_attr(feature = "datasize", derive(DataSize))]
465#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
466#[serde(deny_unknown_fields)]
467pub struct UnbondEra {
468 bonding_purse: URef,
470 era_of_creation: EraId,
472 amount: U512,
474 new_validator: Option<PublicKey>,
476}
477
478impl UnbondEra {
479 pub const fn new(
481 bonding_purse: URef,
482 era_of_creation: EraId,
483 amount: U512,
484 new_validator: Option<PublicKey>,
485 ) -> Self {
486 Self {
487 bonding_purse,
488 era_of_creation,
489 amount,
490 new_validator,
491 }
492 }
493
494 pub fn bonding_purse(&self) -> &URef {
496 &self.bonding_purse
497 }
498
499 pub fn era_of_creation(&self) -> EraId {
501 self.era_of_creation
502 }
503
504 pub fn amount(&self) -> &U512 {
506 &self.amount
507 }
508
509 pub fn new_validator(&self) -> &Option<PublicKey> {
511 &self.new_validator
512 }
513
514 pub fn with_amount(&mut self, amount: U512) {
516 self.amount = amount;
517 }
518}
519
520impl ToBytes for UnbondEra {
521 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
522 let mut result = bytesrepr::allocate_buffer(self)?;
523 result.extend(&self.bonding_purse.to_bytes()?);
524 result.extend(&self.era_of_creation.to_bytes()?);
525 result.extend(&self.amount.to_bytes()?);
526 result.extend(&self.new_validator.to_bytes()?);
527 Ok(result)
528 }
529 fn serialized_length(&self) -> usize {
530 self.bonding_purse.serialized_length()
531 + self.era_of_creation.serialized_length()
532 + self.amount.serialized_length()
533 + self.new_validator.serialized_length()
534 }
535
536 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
537 self.bonding_purse.write_bytes(writer)?;
538 self.era_of_creation.write_bytes(writer)?;
539 self.amount.write_bytes(writer)?;
540 self.new_validator.write_bytes(writer)?;
541 Ok(())
542 }
543}
544
545impl FromBytes for UnbondEra {
546 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
547 let (bonding_purse, remainder) = FromBytes::from_bytes(bytes)?;
548 let (era_of_creation, remainder) = FromBytes::from_bytes(remainder)?;
549 let (amount, remainder) = FromBytes::from_bytes(remainder)?;
550 let (new_validator, remainder) = Option::<PublicKey>::from_bytes(remainder)?;
551
552 Ok((
553 UnbondEra {
554 bonding_purse,
555 era_of_creation,
556 amount,
557 new_validator,
558 },
559 remainder,
560 ))
561 }
562}
563
564impl CLTyped for UnbondEra {
565 fn cl_type() -> CLType {
566 CLType::Any
567 }
568}
569
570mod serde_helpers {
571 use super::UnbondKind;
572 use crate::{PublicKey, URefAddr};
573 use alloc::string::String;
574 use serde::{Deserialize, Serialize};
575
576 #[derive(Serialize, Deserialize)]
577 pub(super) enum HumanReadableUnbondKind {
578 Validator(PublicKey),
579 DelegatedPublicKey(PublicKey),
580 DelegatedPurse(String),
581 }
582
583 #[derive(Serialize, Deserialize)]
584 pub(super) enum NonHumanReadableUnbondKind {
585 Validator(PublicKey),
586 DelegatedPublicKey(PublicKey),
587 DelegatedPurse(URefAddr),
588 }
589
590 impl From<&UnbondKind> for HumanReadableUnbondKind {
591 fn from(unbond_source: &UnbondKind) -> Self {
592 match unbond_source {
593 UnbondKind::Validator(public_key) => {
594 HumanReadableUnbondKind::Validator(public_key.clone())
595 }
596 UnbondKind::DelegatedPublicKey(public_key) => {
597 HumanReadableUnbondKind::DelegatedPublicKey(public_key.clone())
598 }
599 UnbondKind::DelegatedPurse(uref_addr) => {
600 HumanReadableUnbondKind::DelegatedPurse(base16::encode_lower(uref_addr))
601 }
602 }
603 }
604 }
605
606 impl From<&UnbondKind> for NonHumanReadableUnbondKind {
607 fn from(unbond_kind: &UnbondKind) -> Self {
608 match unbond_kind {
609 UnbondKind::Validator(public_key) => {
610 NonHumanReadableUnbondKind::Validator(public_key.clone())
611 }
612 UnbondKind::DelegatedPublicKey(public_key) => {
613 NonHumanReadableUnbondKind::DelegatedPublicKey(public_key.clone())
614 }
615 UnbondKind::DelegatedPurse(uref_addr) => {
616 NonHumanReadableUnbondKind::DelegatedPurse(*uref_addr)
617 }
618 }
619 }
620 }
621}
622
623#[cfg(test)]
624mod tests {
625 use rand::Rng;
626
627 use crate::{
628 bytesrepr,
629 system::auction::{
630 unbond::{Unbond, UnbondKind},
631 UnbondEra,
632 },
633 testing::TestRng,
634 AccessRights, EraId, PublicKey, SecretKey, URef, U512,
635 };
636
637 const BONDING_PURSE: URef = URef::new([14; 32], AccessRights::READ_ADD_WRITE);
638 const ERA_OF_WITHDRAWAL: EraId = EraId::MAX;
639
640 fn validator_public_key() -> PublicKey {
641 let secret_key = SecretKey::ed25519_from_bytes([42; SecretKey::ED25519_LENGTH]).unwrap();
642 PublicKey::from(&secret_key)
643 }
644
645 fn delegated_account_unbond_kind() -> UnbondKind {
646 let secret_key = SecretKey::ed25519_from_bytes([43; SecretKey::ED25519_LENGTH]).unwrap();
647 UnbondKind::DelegatedPublicKey(PublicKey::from(&secret_key))
648 }
649
650 fn amount() -> U512 {
651 U512::max_value() - 1
652 }
653
654 #[test]
655 fn serialization_roundtrip_for_unbond() {
656 let unbond_era = UnbondEra {
657 bonding_purse: BONDING_PURSE,
658 era_of_creation: ERA_OF_WITHDRAWAL,
659 amount: amount(),
660 new_validator: None,
661 };
662
663 let unbond = Unbond {
664 validator_public_key: validator_public_key(),
665 unbond_kind: delegated_account_unbond_kind(),
666 eras: vec![unbond_era],
667 };
668
669 bytesrepr::test_serialization_roundtrip(&unbond);
670 }
671
672 #[test]
673 fn should_be_validator_condition_for_unbond() {
674 let validator_pk = validator_public_key();
675 let validator_unbond = Unbond::new(
676 validator_pk.clone(),
677 UnbondKind::Validator(validator_pk),
678 vec![],
679 );
680 assert!(validator_unbond.is_validator());
681 }
682
683 #[test]
684 fn should_be_delegator_condition_for_unbond() {
685 let delegator_unbond = Unbond::new(
686 validator_public_key(),
687 delegated_account_unbond_kind(),
688 vec![],
689 );
690 assert!(!delegator_unbond.is_validator());
691 }
692
693 #[test]
694 fn purse_serialized_as_string() {
695 let delegator_kind_payload = UnbondKind::DelegatedPurse([1; 32]);
696 let serialized = serde_json::to_string(&delegator_kind_payload).unwrap();
697 assert_eq!(
698 serialized,
699 "{\"DelegatedPurse\":\"0101010101010101010101010101010101010101010101010101010101010101\"}"
700 );
701 }
702
703 #[test]
704 fn given_broken_address_purse_deserialziation_fails() {
705 let failing =
706 "{\"DelegatedPurse\":\"Z101010101010101010101010101010101010101010101010101010101010101\"}";
707 let ret = serde_json::from_str::<UnbondKind>(failing);
708 assert!(ret.is_err());
709 let failing =
710 "{\"DelegatedPurse\":\"01010101010101010101010101010101010101010101010101010101\"}";
711 let ret = serde_json::from_str::<UnbondKind>(failing);
712 assert!(ret.is_err());
713 }
714
715 #[test]
716 fn json_roundtrip() {
717 let rng = &mut TestRng::new();
718
719 let entity = UnbondKind::Validator(PublicKey::random(rng));
720 let json_string = serde_json::to_string_pretty(&entity).unwrap();
721 let decoded: UnbondKind = serde_json::from_str(&json_string).unwrap();
722 assert_eq!(decoded, entity);
723
724 let entity = UnbondKind::DelegatedPublicKey(PublicKey::random(rng));
725 let json_string = serde_json::to_string_pretty(&entity).unwrap();
726 let decoded: UnbondKind = serde_json::from_str(&json_string).unwrap();
727 assert_eq!(decoded, entity);
728
729 let entity = UnbondKind::DelegatedPurse(rng.gen());
730 let json_string = serde_json::to_string_pretty(&entity).unwrap();
731 let decoded: UnbondKind = serde_json::from_str(&json_string).unwrap();
732 assert_eq!(decoded, entity);
733 }
734}