1use std::collections::BTreeMap;
8
9use crate::{
10 common::{crypto::hash::Hash, quantity::Quantity},
11 consensus::{address::Address, beacon::EpochTime},
12};
13
14#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
16pub struct Transfer {
17 pub to: Address,
18 pub amount: Quantity,
19}
20
21#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
23pub struct Withdraw {
24 pub from: Address,
25 pub amount: Quantity,
26}
27
28#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
30pub struct Escrow {
31 pub account: Address,
32 pub amount: Quantity,
33}
34
35#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
37pub struct ReclaimEscrow {
38 pub account: Address,
39 pub shares: Quantity,
40}
41
42#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, cbor::Encode, cbor::Decode)]
44#[repr(i32)]
45pub enum ThresholdKind {
46 KindEntity = 0,
48 KindNodeValidator = 1,
50 KindNodeCompute = 2,
52 KindNodeKeyManager = 4,
54 KindRuntimeCompute = 5,
56 KindRuntimeKeyManager = 6,
58}
59
60#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
62pub struct Account {
63 #[cbor(optional)]
64 pub general: GeneralAccount,
65
66 #[cbor(optional)]
67 pub escrow: EscrowAccount,
68}
69
70#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
72pub struct GeneralAccount {
73 #[cbor(optional)]
74 pub balance: Quantity,
75
76 #[cbor(optional)]
77 pub nonce: u64,
78
79 #[cbor(optional)]
80 pub allowances: BTreeMap<Address, Quantity>,
81}
82
83#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
85pub struct EscrowAccount {
86 #[cbor(optional)]
87 pub active: SharePool,
88
89 #[cbor(optional)]
90 pub debonding: SharePool,
91
92 #[cbor(optional)]
93 pub commission_schedule: CommissionSchedule,
94
95 #[cbor(optional)]
96 pub stake_accumulator: StakeAccumulator,
97}
98
99#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
101pub struct SharePool {
102 #[cbor(optional)]
103 pub balance: Quantity,
104
105 #[cbor(optional)]
106 pub total_shares: Quantity,
107}
108
109#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
111pub struct CommissionSchedule {
112 #[cbor(optional)]
113 pub rates: Vec<CommissionRateStep>,
114
115 #[cbor(optional)]
116 pub bounds: Vec<CommissionRateBoundStep>,
117}
118
119#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
121pub struct CommissionRateStep {
122 pub start: EpochTime,
123 pub rate: Quantity,
124}
125
126#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
128pub struct CommissionRateBoundStep {
129 #[cbor(optional)]
130 pub start: EpochTime,
131
132 #[cbor(optional)]
133 pub rate_min: Quantity,
134
135 #[cbor(optional)]
136 pub rate_max: Quantity,
137}
138
139#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
141pub struct StakeAccumulator {
142 #[cbor(optional)]
143 pub claims: BTreeMap<StakeClaim, Vec<StakeThreshold>>,
144}
145
146pub type StakeClaim = String;
148
149#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
151pub struct StakeThreshold {
152 #[cbor(optional)]
153 pub global: Option<ThresholdKind>,
154
155 #[cbor(optional, rename = "const")]
156 pub constant: Option<Quantity>,
157}
158
159#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
161pub struct Delegation {
162 pub shares: Quantity,
163}
164
165#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
167pub struct DebondingDelegation {
168 pub shares: Quantity,
169
170 #[cbor(rename = "debond_end")]
171 pub debond_end_time: EpochTime,
172}
173
174#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, cbor::Encode, cbor::Decode)]
176#[repr(u8)]
177pub enum SlashReason {
178 RuntimeIncorrectResults = 0x80,
180 RuntimeEquivocation = 0x81,
183 RuntimeLiveness = 0x82,
185}
186
187#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
189pub struct Slash {
190 pub amount: Quantity,
191 pub freeze_interval: EpochTime,
192}
193
194#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
196pub struct TransferResult {
197 pub from: Address,
198 pub to: Address,
199 pub amount: Quantity,
200}
201
202#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
204pub struct AddEscrowResult {
205 pub owner: Address,
206 pub escrow: Address,
207 pub amount: Quantity,
208 pub new_shares: Quantity,
209}
210
211#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
213pub struct ReclaimEscrowResult {
214 pub owner: Address,
215 pub escrow: Address,
216 pub amount: Quantity,
217 pub remaining_shares: Quantity,
218 pub debonding_shares: Quantity,
219 pub debond_end_time: EpochTime,
220}
221
222#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
224pub struct WithdrawResult {
225 pub owner: Address,
226 pub beneficiary: Address,
227 pub allowance: Quantity,
228 pub amount_change: Quantity,
229}
230
231#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
233pub struct Event {
234 #[cbor(optional)]
235 pub height: i64,
236 #[cbor(optional)]
237 pub tx_hash: Hash,
238
239 #[cbor(optional)]
241 pub transfer: Option<TransferEvent>,
242 #[cbor(optional)]
243 pub burn: Option<BurnEvent>,
244 #[cbor(optional)]
245 pub escrow: Option<EscrowEvent>,
246 #[cbor(optional)]
247 pub allowance_change: Option<AllowanceChangeEvent>,
248}
249
250#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
252pub struct TransferEvent {
253 pub from: Address,
254 pub to: Address,
255 pub amount: Quantity,
256}
257
258#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
260pub struct BurnEvent {
261 pub owner: Address,
262 pub amount: Quantity,
263}
264
265#[derive(Clone, Debug, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
267pub enum EscrowEvent {
268 #[cbor(rename = "add")]
270 Add {
271 owner: Address,
272 escrow: Address,
273 amount: Quantity,
274 new_shares: Quantity,
275 },
276
277 #[cbor(rename = "take")]
279 Take {
280 owner: Address,
281 amount: Quantity,
283 debonding_amount: Quantity,
285 },
286
287 #[cbor(rename = "debonding_start")]
293 DebondingStart {
294 owner: Address,
295 escrow: Address,
296 amount: Quantity,
297 active_shares: Quantity,
298 debonding_shares: Quantity,
299 debond_end_time: EpochTime,
300 },
301
302 #[cbor(rename = "reclaim")]
305 Reclaim {
306 owner: Address,
307 escrow: Address,
308 amount: Quantity,
309 shares: Quantity,
310 },
311}
312
313#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
315pub struct AllowanceChangeEvent {
316 pub owner: Address,
317 pub beneficiary: Address,
318 pub allowance: Quantity,
319 #[cbor(optional)]
320 pub negative: bool,
321 pub amount_change: Quantity,
322}
323
324#[cfg(test)]
325mod tests {
326 use base64::prelude::*;
327
328 use super::*;
329 use crate::{
330 common::crypto::signature::PublicKey,
331 consensus::address::{COMMON_POOL_ADDRESS, GOVERNANCE_DEPOSITS_ADDRESS},
332 };
333
334 #[test]
335 fn test_consistent_accounts() {
336 let tcs = vec![
337 ("oA==", Account::default()),
338 (
339 "oWdnZW5lcmFsomVub25jZRghZ2JhbGFuY2VBCg==",
340 Account {
341 general: GeneralAccount {
342 balance: Quantity::from(10u32),
343 nonce: 33,
344 ..Default::default()
345 },
346 ..Default::default()
347 },
348 ),
349 (
350 "oWdnZW5lcmFsoWphbGxvd2FuY2VzolUAdU/0RxQ6XsX0cbMPhna5TVaxV1BBIVUA98Te1iET4sKC6oZyI6VE7VXWum5BZA==",
351 {
352 Account {
353 general: GeneralAccount {
354 allowances: [
355 (COMMON_POOL_ADDRESS.clone(), Quantity::from(100u32)),
356 (GOVERNANCE_DEPOSITS_ADDRESS.clone(), Quantity::from(33u32))
357 ].iter().cloned().collect(),
358 ..Default::default()
359 },
360 ..Default::default()
361 }
362 },
363 ),
364 (
365 "oWZlc2Nyb3ejZmFjdGl2ZaJnYmFsYW5jZUIETGx0b3RhbF9zaGFyZXNBC3FzdGFrZV9hY2N1bXVsYXRvcqFmY2xhaW1zoWZlbnRpdHmCoWVjb25zdEFNoWZnbG9iYWwCc2NvbW1pc3Npb25fc2NoZWR1bGWhZmJvdW5kc4GjZXN0YXJ0GCFocmF0ZV9tYXhCA+hocmF0ZV9taW5BCg==",
366 Account {
367 escrow: EscrowAccount {
368 active: SharePool{
369 balance: Quantity::from(1100u32),
370 total_shares: Quantity::from(11u32),
371 },
372 debonding: SharePool::default(),
373 commission_schedule: CommissionSchedule {
374 bounds: vec![CommissionRateBoundStep{
375 start: 33,
376 rate_min: Quantity::from(10u32),
377 rate_max: Quantity::from(1000u32),
378 }],
379 ..Default::default()
380 },
381 stake_accumulator: StakeAccumulator {
382 claims: [
383 (
384 "entity".to_string(),
385 vec![
386 StakeThreshold{
387 constant: Some(Quantity::from(77u32)),
388 ..Default::default()
389 },
390 StakeThreshold{
391 global: Some(ThresholdKind::KindNodeCompute),
392 ..Default::default()
393 },
394 ]
395 )
396 ].iter().cloned().collect()
397 }
398 },
399 ..Default::default()
400 },
401 )
402 ];
403 for (encoded_base64, rr) in tcs {
404 let dec: Account = cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
405 .expect("account should deserialize correctly");
406 assert_eq!(dec, rr, "decoded account should match the expected value");
407 }
408 }
409
410 #[test]
411 fn test_consistent_delegations() {
412 let tcs = vec![
413 ("oWZzaGFyZXNA", Delegation::default()),
414 (
415 "oWZzaGFyZXNBZA==",
416 Delegation {
417 shares: Quantity::from(100u32),
418 },
419 ),
420 ];
421 for (encoded_base64, rr) in tcs {
422 let dec: Delegation =
423 cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
424 .expect("delegation should deserialize correctly");
425 assert_eq!(dec, rr, "decoded account should match the expected value");
426 }
427 }
428
429 #[test]
430 fn test_consistent_debonding_delegations() {
431 let tcs = vec![
432 (
433 "omZzaGFyZXNAamRlYm9uZF9lbmQA",
434 DebondingDelegation::default(),
435 ),
436 (
437 "omZzaGFyZXNBZGpkZWJvbmRfZW5kFw==",
438 DebondingDelegation {
439 shares: Quantity::from(100u32),
440 debond_end_time: 23,
441 },
442 ),
443 ];
444 for (encoded_base64, rr) in tcs {
445 let dec: DebondingDelegation =
446 cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
447 .expect("debonding delegation should deserialize correctly");
448 assert_eq!(dec, rr, "decoded account should match the expected value");
449 }
450 }
451
452 #[test]
453 fn test_consistent_transfer_results() {
454 let addr1 = Address::from_pk(&PublicKey::from(
455 "aaafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
456 ));
457 let addr2 = Address::from_pk(&PublicKey::from(
458 "bbbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
459 ));
460
461 let tcs = vec![
462 ("o2J0b1UAAAAAAAAAAAAAAAAAAAAAAAAAAABkZnJvbVUAAAAAAAAAAAAAAAAAAAAAAAAAAABmYW1vdW50QA==", TransferResult::default()),
463 (
464 "o2J0b1UAuRI5eJXmRwxR+r7MndyD9wrthqFkZnJvbVUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNmYW1vdW50QWQ=",
465 TransferResult {
466 amount: Quantity::from(100u32),
467 from: addr1,
468 to: addr2,
469 },
470 ),
471 ];
472 for (encoded_base64, rr) in tcs {
473 let dec: TransferResult =
474 cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
475 .expect("transfer result should deserialize correctly");
476 assert_eq!(dec, rr, "decoded result should match the expected value");
477 }
478 }
479
480 #[test]
481 fn test_consistent_withdraw_results() {
482 let addr1 = Address::from_pk(&PublicKey::from(
483 "aaafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
484 ));
485 let addr2 = Address::from_pk(&PublicKey::from(
486 "bbbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
487 ));
488
489 let tcs = vec![
490 ("pGVvd25lclUAAAAAAAAAAAAAAAAAAAAAAAAAAABpYWxsb3dhbmNlQGtiZW5lZmljaWFyeVUAAAAAAAAAAAAAAAAAAAAAAAAAAABtYW1vdW50X2NoYW5nZUA=", WithdrawResult::default()),
491 (
492 "pGVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNpYWxsb3dhbmNlQQprYmVuZWZpY2lhcnlVALkSOXiV5kcMUfq+zJ3cg/cK7YahbWFtb3VudF9jaGFuZ2VBBQ==",
493 WithdrawResult {
494 owner: addr1,
495 beneficiary: addr2,
496 allowance: Quantity::from(10u32),
497 amount_change: Quantity::from(5u32),
498 },
499 ),
500 ];
501 for (encoded_base64, rr) in tcs {
502 let dec: WithdrawResult =
503 cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
504 .expect("withdraw result should deserialize correctly");
505 assert_eq!(dec, rr, "decoded result should match the expected value");
506 }
507 }
508
509 #[test]
510 fn test_consistent_add_escrow_results() {
511 let addr1 = Address::from_pk(&PublicKey::from(
512 "aaafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
513 ));
514 let addr2 = Address::from_pk(&PublicKey::from(
515 "bbbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
516 ));
517
518 let tcs = vec![
519 ("pGVvd25lclUAAAAAAAAAAAAAAAAAAAAAAAAAAABmYW1vdW50QGZlc2Nyb3dVAAAAAAAAAAAAAAAAAAAAAAAAAAAAam5ld19zaGFyZXNA", AddEscrowResult::default()),
520 (
521 "pGVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNmYW1vdW50QWRmZXNjcm93VQC5Ejl4leZHDFH6vsyd3IP3Cu2GoWpuZXdfc2hhcmVzQQU=",
522 AddEscrowResult {
523 owner: addr1,
524 escrow: addr2,
525 amount: Quantity::from(100u32),
526 new_shares: Quantity::from(5u32),
527 },
528 ),
529 ];
530 for (encoded_base64, rr) in tcs {
531 let dec: AddEscrowResult =
532 cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
533 .expect("add escrow result should deserialize correctly");
534 assert_eq!(dec, rr, "decoded result should match the expected value");
535 }
536 }
537
538 #[test]
539 fn test_consistent_reclaim_escrow_results() {
540 let addr1 = Address::from_pk(&PublicKey::from(
541 "aaafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
542 ));
543 let addr2 = Address::from_pk(&PublicKey::from(
544 "bbbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
545 ));
546
547 let tcs = vec![
548 ("pmVvd25lclUAAAAAAAAAAAAAAAAAAAAAAAAAAABmYW1vdW50QGZlc2Nyb3dVAAAAAAAAAAAAAAAAAAAAAAAAAAAAb2RlYm9uZF9lbmRfdGltZQBwZGVib25kaW5nX3NoYXJlc0BwcmVtYWluaW5nX3NoYXJlc0A=", ReclaimEscrowResult::default()),
549 (
550 "pmVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNmYW1vdW50QWRmZXNjcm93VQC5Ejl4leZHDFH6vsyd3IP3Cu2GoW9kZWJvbmRfZW5kX3RpbWUYKnBkZWJvbmRpbmdfc2hhcmVzQRlwcmVtYWluaW5nX3NoYXJlc0Ey",
551 ReclaimEscrowResult {
552 owner: addr1,
553 escrow: addr2,
554 amount: Quantity::from(100u32),
555 remaining_shares: Quantity::from(50u32),
556 debonding_shares: Quantity::from(25u32),
557 debond_end_time: 42,
558 },
559 ),
560 ];
561 for (encoded_base64, rr) in tcs {
562 let dec: ReclaimEscrowResult =
563 cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
564 .expect("reclaim escrow result should deserialize correctly");
565 assert_eq!(dec, rr, "decoded result should match the expected value");
566 }
567 }
568
569 #[test]
570 fn test_consistent_events() {
571 let addr1 = Address::from_pk(&PublicKey::from(
572 "aaafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
573 ));
574 let addr2 = Address::from_pk(&PublicKey::from(
575 "bbbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
576 ));
577 let tx_hash = Hash::empty_hash();
578
579 let tcs = vec![
580 (
581 "oWd0eF9oYXNoWCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
582 Event::default(),
583 ),
584 (
585 "omZoZWlnaHQYKmd0eF9oYXNoWCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
586 Event {
587 height: 42,
588 ..Default::default()
589 },
590 ),
591 (
592 "omZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWeg==",
593 Event {
594 height: 42,
595 tx_hash,
596 ..Default::default()
597 },
598 ),
599
600 (
602 "o2ZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWemh0cmFuc2ZlcqNidG9VALkSOXiV5kcMUfq+zJ3cg/cK7YahZGZyb21VACByFDSJP2FsCYFI4s+fmePigm4TZmFtb3VudEFk",
603 Event {
604 height: 42,
605 tx_hash,
606 transfer: Some(TransferEvent {
607 from: addr1.clone(),
608 to: addr2.clone(),
609 amount: 100u32.into(),
610 }),
611 ..Default::default()
612 },
613 ),
614
615 (
617 "o2RidXJuomVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNmYW1vdW50QWRmaGVpZ2h0GCpndHhfaGFzaFggxnK40e9W7Sirh8NiLFEUBpvdOte4+XN0mNDAHs7wlno=",
618 Event {
619 height: 42,
620 tx_hash,
621 burn: Some(BurnEvent {
622 owner: addr1.clone(),
623 amount: 100u32.into(),
624 }),
625 ..Default::default()
626 },
627 ),
628
629 (
631 "o2Zlc2Nyb3ehY2FkZKRlb3duZXJVACByFDSJP2FsCYFI4s+fmePigm4TZmFtb3VudEFkZmVzY3Jvd1UAuRI5eJXmRwxR+r7MndyD9wrthqFqbmV3X3NoYXJlc0EyZmhlaWdodBgqZ3R4X2hhc2hYIMZyuNHvVu0oq4fDYixRFAab3TrXuPlzdJjQwB7O8JZ6",
632 Event {
633 height: 42,
634 tx_hash,
635 escrow: Some(EscrowEvent::Add {
636 owner: addr1.clone(),
637 escrow: addr2.clone(),
638 amount: 100u32.into(),
639 new_shares: 50u32.into(),
640 }),
641 ..Default::default()
642 },
643 ),
644 (
645 "o2Zlc2Nyb3ehZHRha2WjZW93bmVyVQAgchQ0iT9hbAmBSOLPn5nj4oJuE2ZhbW91bnRBZHBkZWJvbmRpbmdfYW1vdW50QRRmaGVpZ2h0GCpndHhfaGFzaFggxnK40e9W7Sirh8NiLFEUBpvdOte4+XN0mNDAHs7wlno=",
646 Event {
647 height: 42,
648 tx_hash,
649 escrow: Some(EscrowEvent::Take {
650 owner: addr1.clone(),
651 amount: 100u32.into(),
652 debonding_amount: 20u32.into()
653 }),
654 ..Default::default()
655 },
656 ),
657 (
658 "o2Zlc2Nyb3ehb2RlYm9uZGluZ19zdGFydKZlb3duZXJVACByFDSJP2FsCYFI4s+fmePigm4TZmFtb3VudEFkZmVzY3Jvd1UAuRI5eJXmRwxR+r7MndyD9wrthqFtYWN0aXZlX3NoYXJlc0Eyb2RlYm9uZF9lbmRfdGltZRgqcGRlYm9uZGluZ19zaGFyZXNBGWZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWeg==",
659 Event {
660 height: 42,
661 tx_hash,
662 escrow: Some(EscrowEvent::DebondingStart {
663 owner: addr1.clone(),
664 escrow: addr2.clone(),
665 amount: 100u32.into(),
666 active_shares: 50u32.into(),
667 debonding_shares: 25u32.into(),
668 debond_end_time: 42,
669 }),
670 ..Default::default()
671 },
672 ),
673 (
674 "o2Zlc2Nyb3ehZ3JlY2xhaW2kZW93bmVyVQAgchQ0iT9hbAmBSOLPn5nj4oJuE2ZhbW91bnRBZGZlc2Nyb3dVALkSOXiV5kcMUfq+zJ3cg/cK7YahZnNoYXJlc0EZZmhlaWdodBgqZ3R4X2hhc2hYIMZyuNHvVu0oq4fDYixRFAab3TrXuPlzdJjQwB7O8JZ6",
675 Event {
676 height: 42,
677 tx_hash,
678 escrow: Some(EscrowEvent::Reclaim {
679 owner: addr1.clone(),
680 escrow: addr2.clone(),
681 amount: 100u32.into(),
682 shares: 25u32.into(),
683 }),
684 ..Default::default()
685 },
686 ),
687
688 (
690 "o2ZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWenBhbGxvd2FuY2VfY2hhbmdlpGVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNpYWxsb3dhbmNlQWRrYmVuZWZpY2lhcnlVALkSOXiV5kcMUfq+zJ3cg/cK7YahbWFtb3VudF9jaGFuZ2VBMg==",
691 Event {
692 height: 42,
693 tx_hash,
694 allowance_change: Some(AllowanceChangeEvent {
695 owner: addr1.clone(),
696 beneficiary: addr2.clone(),
697 allowance: 100u32.into(),
698 negative: false,
699 amount_change: 50u32.into(),
700 }),
701 ..Default::default()
702 },
703 ),
704 (
705 "o2ZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWenBhbGxvd2FuY2VfY2hhbmdlpWVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNobmVnYXRpdmX1aWFsbG93YW5jZUFka2JlbmVmaWNpYXJ5VQC5Ejl4leZHDFH6vsyd3IP3Cu2GoW1hbW91bnRfY2hhbmdlQTI=",
706 Event {
707 height: 42,
708 tx_hash,
709 allowance_change: Some(AllowanceChangeEvent {
710 owner: addr1.clone(),
711 beneficiary: addr2.clone(),
712 allowance: 100u32.into(),
713 negative: true,
714 amount_change: 50u32.into(),
715 }),
716 ..Default::default()
717 },
718 ),
719 ];
720 for (encoded_base64, ev) in tcs {
721 let dec: Event = cbor::from_slice(&BASE64_STANDARD.decode(encoded_base64).unwrap())
722 .expect("event should deserialize correctly");
723 assert_eq!(dec, ev, "decoded event should match the expected value");
724 }
725 }
726}