1use std::collections::BTreeMap;
4use std::fmt::Display;
5use std::num::ParseIntError;
6use std::str::FromStr;
7
8use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
9use masp_primitives::asset_type::AssetType;
10use masp_primitives::sapling::ViewingKey;
11use masp_primitives::transaction::TransparentAddress;
12pub use masp_primitives::transaction::{
13 Transaction as MaspTransaction, TxId as TxIdInner,
14};
15use masp_primitives::zip32::{ExtendedKey, PseudoExtendedKey};
16use namada_macros::BorshDeserializer;
17#[cfg(feature = "migrations")]
18use namada_migrations::*;
19use ripemd::Digest as RipemdDigest;
20use serde::{Deserialize, Deserializer, Serialize, Serializer};
21use sha2::Sha256;
22
23use crate::address::{Address, DecodeError, HASH_HEX_LEN, IBC, MASP};
24use crate::borsh::BorshSerializeExt;
25use crate::chain::Epoch;
26use crate::impl_display_and_from_str_via_format;
27use crate::string_encoding::{
28 self, MASP_EXT_FULL_VIEWING_KEY_HRP, MASP_EXT_SPENDING_KEY_HRP,
29 MASP_PAYMENT_ADDRESS_HRP,
30};
31use crate::token::{Denomination, MaspDigitPos};
32
33pub fn serialize_txid<S>(txid: &TxIdInner, s: S) -> Result<S::Ok, S::Error>
35where
36 S: Serializer,
37{
38 s.serialize_bytes(txid.as_ref())
39}
40
41pub fn deserialize_txid<'de, D>(deserializer: D) -> Result<TxIdInner, D::Error>
43where
44 D: Deserializer<'de>,
45{
46 Ok(TxIdInner::from_bytes(Deserialize::deserialize(
47 deserializer,
48 )?))
49}
50
51#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
53#[derive(
54 Serialize,
55 Deserialize,
56 Clone,
57 BorshSerialize,
58 BorshDeserialize,
59 BorshSchema,
60 Debug,
61 Eq,
62 PartialEq,
63 Copy,
64 Ord,
65 PartialOrd,
66 Hash,
67)]
68pub struct MaspTxId(
69 #[serde(
70 serialize_with = "serialize_txid",
71 deserialize_with = "deserialize_txid"
72 )]
73 pub TxIdInner,
74);
75
76impl From<TxIdInner> for MaspTxId {
77 fn from(txid: TxIdInner) -> Self {
78 Self(txid)
79 }
80}
81
82impl Display for MaspTxId {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86}
87
88#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
91#[derive(
92 BorshSerialize,
93 BorshDeserialize,
94 BorshDeserializer,
95 BorshSchema,
96 Clone,
97 Copy,
98 Debug,
99 PartialOrd,
100 Ord,
101 PartialEq,
102 Eq,
103 Hash,
104 Serialize,
105 Deserialize,
106)]
107pub struct MaspEpoch(Epoch);
108
109impl Display for MaspEpoch {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 write!(f, "{}", self.0)
112 }
113}
114
115impl FromStr for MaspEpoch {
116 type Err = ParseIntError;
117
118 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
119 let inner: Epoch = Epoch::from_str(s)?;
120 Ok(Self(inner))
121 }
122}
123
124impl MaspEpoch {
125 pub fn try_from_epoch(
128 epoch: Epoch,
129 masp_epoch_multiplier: u64,
130 ) -> Result<Self, &'static str> {
131 Ok(Self(
132 epoch
133 .checked_div(masp_epoch_multiplier)
134 .ok_or("Masp epoch multiplier cannot be 0")?,
135 ))
136 }
137
138 pub const fn zero() -> Self {
140 Self(Epoch(0))
141 }
142
143 pub fn prev(&self) -> Option<Self> {
145 Some(Self(self.0.checked_sub(1)?))
146 }
147
148 pub fn next(&self) -> Option<Self> {
150 Some(Self(self.0.checked_add(1)?))
151 }
152
153 #[cfg(any(test, feature = "testing"))]
155 pub const fn new(epoch: u64) -> Self {
156 Self(Epoch(epoch))
157 }
158}
159
160#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
162#[derive(
163 BorshSerialize,
164 BorshDeserialize,
165 BorshDeserializer,
166 BorshSchema,
167 Clone,
168 Debug,
169 PartialOrd,
170 Ord,
171 PartialEq,
172 Eq,
173 Hash,
174 Serialize,
175 Deserialize,
176)]
177pub struct AssetData {
178 pub token: Address,
180 pub denom: Denomination,
182 pub position: MaspDigitPos,
184 pub epoch: Option<MaspEpoch>,
186}
187
188impl AssetData {
189 pub fn encode(&self) -> Result<AssetType, std::io::Error> {
191 let token_bytes = self.serialize_to_vec();
193 AssetType::new(token_bytes.as_ref()).map_err(|_| {
195 std::io::Error::new(
196 std::io::ErrorKind::Other,
197 "unable to create asset type".to_string(),
198 )
199 })
200 }
201
202 pub fn redate(self, to: MaspEpoch) -> Self {
205 if self.epoch.is_some() {
206 Self {
207 epoch: Some(to),
208 ..self
209 }
210 } else {
211 self
212 }
213 }
214
215 pub fn redate_to_next_epoch(self) -> Self {
217 if let Some(next) = self.epoch.as_ref().and_then(MaspEpoch::next) {
218 Self {
219 epoch: Some(next),
220 ..self
221 }
222 } else {
223 self
224 }
225 }
226
227 pub fn undate(self) -> Self {
229 Self {
230 epoch: None,
231 ..self
232 }
233 }
234}
235
236pub fn encode_asset_type(
238 token: Address,
239 denom: Denomination,
240 position: MaspDigitPos,
241 epoch: Option<MaspEpoch>,
242) -> Result<AssetType, std::io::Error> {
243 AssetData {
244 token,
245 denom,
246 position,
247 epoch,
248 }
249 .encode()
250}
251
252pub fn encode_reward_asset_types(
254 native_token: &Address,
255) -> Result<[AssetType; 4], std::io::Error> {
256 use crate::token::{MaspDigitPos, NATIVE_MAX_DECIMAL_PLACES};
257 Ok([
258 encode_asset_type(
259 native_token.clone(),
260 NATIVE_MAX_DECIMAL_PLACES.into(),
261 MaspDigitPos::Zero,
262 Some(MaspEpoch::zero()),
263 )?,
264 encode_asset_type(
265 native_token.clone(),
266 NATIVE_MAX_DECIMAL_PLACES.into(),
267 MaspDigitPos::One,
268 Some(MaspEpoch::zero()),
269 )?,
270 encode_asset_type(
271 native_token.clone(),
272 NATIVE_MAX_DECIMAL_PLACES.into(),
273 MaspDigitPos::Two,
274 Some(MaspEpoch::zero()),
275 )?,
276 encode_asset_type(
277 native_token.clone(),
278 NATIVE_MAX_DECIMAL_PLACES.into(),
279 MaspDigitPos::Three,
280 Some(MaspEpoch::zero()),
281 )?,
282 ])
283}
284
285pub type TokenMap = BTreeMap<String, Address>;
287
288const PAYMENT_ADDRESS_SIZE: usize = 43;
290
291#[derive(
293 Clone,
294 Debug,
295 Copy,
296 Hash,
297 BorshSerialize,
298 BorshDeserialize,
299 BorshDeserializer,
300 Eq,
301 PartialEq,
302 PartialOrd,
303 Ord,
304)]
305pub struct ExtendedViewingKey(masp_primitives::zip32::ExtendedFullViewingKey);
306
307impl ExtendedViewingKey {
308 pub fn to_bytes(&self) -> Vec<u8> {
310 let mut bytes = [0; 169];
311 self.0
312 .write(&mut bytes[..])
313 .expect("should be able to serialize an ExtendedFullViewingKey");
314 bytes.to_vec()
315 }
316
317 pub fn decode_bytes(bytes: &[u8]) -> Result<Self, std::io::Error> {
319 masp_primitives::zip32::ExtendedFullViewingKey::read(&mut &bytes[..])
320 .map(Self)
321 }
322
323 pub fn as_viewing_key(&self) -> ViewingKey {
325 self.0.fvk.vk
326 }
327}
328
329impl string_encoding::Format for ExtendedViewingKey {
330 type EncodedBytes<'a> = Vec<u8>;
331
332 const HRP: string_encoding::Hrp =
333 string_encoding::Hrp::parse_unchecked(MASP_EXT_FULL_VIEWING_KEY_HRP);
334
335 fn to_bytes(&self) -> Vec<u8> {
336 self.to_bytes()
337 }
338
339 fn decode_bytes(
340 bytes: &[u8],
341 ) -> Result<Self, string_encoding::DecodeError> {
342 Self::decode_bytes(bytes).map_err(DecodeError::InvalidBytes)
343 }
344}
345
346impl_display_and_from_str_via_format!(ExtendedViewingKey);
347
348impl string_encoding::Format for PaymentAddress {
349 type EncodedBytes<'a> = Vec<u8>;
350
351 const HRP: string_encoding::Hrp =
352 string_encoding::Hrp::parse_unchecked(MASP_PAYMENT_ADDRESS_HRP);
353
354 fn to_bytes(&self) -> Vec<u8> {
355 let mut bytes = Vec::with_capacity(PAYMENT_ADDRESS_SIZE);
356 bytes.extend_from_slice(self.0.to_bytes().as_slice());
357 bytes
358 }
359
360 fn decode_bytes(
361 bytes: &[u8],
362 ) -> Result<Self, string_encoding::DecodeError> {
363 if bytes.len() != PAYMENT_ADDRESS_SIZE {
364 return Err(DecodeError::InvalidInnerEncoding(format!(
365 "expected {PAYMENT_ADDRESS_SIZE} bytes for the payment address"
366 )));
367 }
368 let payment_addr =
369 masp_primitives::sapling::PaymentAddress::from_bytes(&{
370 let mut payment_addr = [0u8; PAYMENT_ADDRESS_SIZE];
371 payment_addr.copy_from_slice(&bytes[0..]);
372 payment_addr
373 })
374 .ok_or_else(|| {
375 DecodeError::InvalidInnerEncoding(
376 "invalid payment address provided".to_string(),
377 )
378 })?;
379 Ok(Self(payment_addr))
380 }
381}
382
383impl_display_and_from_str_via_format!(PaymentAddress);
384
385impl From<ExtendedViewingKey>
386 for masp_primitives::zip32::ExtendedFullViewingKey
387{
388 fn from(key: ExtendedViewingKey) -> Self {
389 key.0
390 }
391}
392
393impl From<masp_primitives::zip32::ExtendedFullViewingKey>
394 for ExtendedViewingKey
395{
396 fn from(key: masp_primitives::zip32::ExtendedFullViewingKey) -> Self {
397 Self(key)
398 }
399}
400
401impl From<ExtendedViewingKey> for masp_primitives::sapling::ViewingKey {
402 fn from(value: ExtendedViewingKey) -> Self {
403 let fvk = masp_primitives::zip32::ExtendedFullViewingKey::from(value);
404 fvk.fvk.vk
405 }
406}
407
408impl serde::Serialize for ExtendedViewingKey {
409 fn serialize<S>(
410 &self,
411 serializer: S,
412 ) -> std::result::Result<S::Ok, S::Error>
413 where
414 S: serde::Serializer,
415 {
416 let encoded = self.to_string();
417 serde::Serialize::serialize(&encoded, serializer)
418 }
419}
420
421impl<'de> serde::Deserialize<'de> for ExtendedViewingKey {
422 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
423 where
424 D: serde::Deserializer<'de>,
425 {
426 use serde::de::Error;
427 let encoded: String = serde::Deserialize::deserialize(deserializer)?;
428 Self::from_str(&encoded).map_err(D::Error::custom)
429 }
430}
431
432#[derive(
434 Clone,
435 Debug,
436 Copy,
437 PartialOrd,
438 Ord,
439 Eq,
440 PartialEq,
441 Hash,
442 BorshSerialize,
443 BorshDeserialize,
444 BorshDeserializer,
445)]
446pub struct PaymentAddress(masp_primitives::sapling::PaymentAddress);
447
448impl PaymentAddress {
449 pub fn hash(&self) -> String {
451 let bytes = self.0.serialize_to_vec();
452 let mut hasher = Sha256::new();
453 hasher.update(bytes);
454 format!("{:.width$X}", hasher.finalize(), width = HASH_HEX_LEN)
456 }
457}
458
459impl From<PaymentAddress> for masp_primitives::sapling::PaymentAddress {
460 fn from(addr: PaymentAddress) -> Self {
461 addr.0
462 }
463}
464
465impl From<masp_primitives::sapling::PaymentAddress> for PaymentAddress {
466 fn from(addr: masp_primitives::sapling::PaymentAddress) -> Self {
467 Self(addr)
468 }
469}
470
471impl serde::Serialize for PaymentAddress {
472 fn serialize<S>(
473 &self,
474 serializer: S,
475 ) -> std::result::Result<S::Ok, S::Error>
476 where
477 S: serde::Serializer,
478 {
479 let encoded = self.to_string();
480 serde::Serialize::serialize(&encoded, serializer)
481 }
482}
483
484impl<'de> serde::Deserialize<'de> for PaymentAddress {
485 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
486 where
487 D: serde::Deserializer<'de>,
488 {
489 use serde::de::Error;
490 let encoded: String = serde::Deserialize::deserialize(deserializer)?;
491 Self::from_str(&encoded).map_err(D::Error::custom)
492 }
493}
494
495#[derive(
497 Clone,
498 Debug,
499 Copy,
500 BorshSerialize,
501 BorshDeserialize,
502 BorshDeserializer,
503 Hash,
504 Eq,
505 PartialEq,
506)]
507pub struct ExtendedSpendingKey(masp_primitives::zip32::ExtendedSpendingKey);
508
509impl string_encoding::Format for ExtendedSpendingKey {
510 type EncodedBytes<'a> = Vec<u8>;
511
512 const HRP: string_encoding::Hrp =
513 string_encoding::Hrp::parse_unchecked(MASP_EXT_SPENDING_KEY_HRP);
514
515 fn to_bytes(&self) -> Vec<u8> {
516 let mut bytes = [0; 169];
517 self.0
518 .write(&mut &mut bytes[..])
519 .expect("should be able to serialize an ExtendedSpendingKey");
520 bytes.to_vec()
521 }
522
523 fn decode_bytes(
524 bytes: &[u8],
525 ) -> Result<Self, string_encoding::DecodeError> {
526 masp_primitives::zip32::ExtendedSpendingKey::read(&mut &bytes[..])
527 .map_err(|op| DecodeError::InvalidInnerEncoding(op.to_string()))
528 .map(Self)
529 }
530}
531
532impl_display_and_from_str_via_format!(ExtendedSpendingKey);
533
534impl ExtendedSpendingKey {
535 pub fn to_viewing_key(&self) -> ExtendedViewingKey {
537 ExtendedViewingKey::from(
538 #[allow(deprecated)]
539 {
540 self.0.to_extended_full_viewing_key()
541 },
542 )
543 }
544}
545
546impl From<ExtendedSpendingKey> for masp_primitives::zip32::ExtendedSpendingKey {
547 fn from(key: ExtendedSpendingKey) -> Self {
548 key.0
549 }
550}
551
552impl From<masp_primitives::zip32::ExtendedSpendingKey> for ExtendedSpendingKey {
553 fn from(key: masp_primitives::zip32::ExtendedSpendingKey) -> Self {
554 Self(key)
555 }
556}
557
558impl serde::Serialize for ExtendedSpendingKey {
559 fn serialize<S>(
560 &self,
561 serializer: S,
562 ) -> std::result::Result<S::Ok, S::Error>
563 where
564 S: serde::Serializer,
565 {
566 let encoded = self.to_string();
567 serde::Serialize::serialize(&encoded, serializer)
568 }
569}
570
571impl<'de> serde::Deserialize<'de> for ExtendedSpendingKey {
572 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
573 where
574 D: serde::Deserializer<'de>,
575 {
576 use serde::de::Error;
577 let encoded: String = serde::Deserialize::deserialize(deserializer)?;
578 Self::from_str(&encoded).map_err(D::Error::custom)
579 }
580}
581
582#[allow(clippy::large_enum_variant)]
584#[derive(Debug, Clone, Hash, Eq, PartialEq)]
585pub enum TransferSource {
586 Address(Address),
588 ExtendedKey(PseudoExtendedKey),
590}
591
592impl TransferSource {
593 pub fn effective_address(&self) -> Address {
595 match self {
596 Self::Address(x) => x.clone(),
597 Self::ExtendedKey(_) => MASP,
600 }
601 }
602
603 pub fn spending_key(&self) -> Option<PseudoExtendedKey> {
605 match self {
606 Self::ExtendedKey(x) => Some(*x),
607 _ => None,
608 }
609 }
610
611 pub fn spending_key_mut(&mut self) -> Option<&mut PseudoExtendedKey> {
613 match self {
614 Self::ExtendedKey(x) => Some(x),
615 _ => None,
616 }
617 }
618
619 pub fn address(&self) -> Option<Address> {
621 match self {
622 Self::Address(x) => Some(x.clone()),
623 _ => None,
624 }
625 }
626
627 pub fn t_addr_data(&self) -> Option<TAddrData> {
629 match self {
630 Self::Address(x) => Some(TAddrData::Addr(x.clone())),
631 _ => None,
632 }
633 }
634}
635
636impl Display for TransferSource {
637 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
638 match self {
639 Self::Address(x) => x.fmt(f),
640 Self::ExtendedKey(x) => {
641 ExtendedViewingKey::from(x.to_viewing_key()).fmt(f)
642 }
643 }
644 }
645}
646
647#[derive(
649 Debug,
650 Clone,
651 PartialEq,
652 Eq,
653 BorshDeserialize,
654 BorshSerialize,
655 BorshDeserializer,
656)]
657pub enum TAddrData {
658 Addr(Address),
660 Ibc(String),
662}
663
664impl TAddrData {
665 pub fn effective_address(&self) -> Address {
667 match self {
668 Self::Addr(x) => x.clone(),
669 Self::Ibc(_) => IBC,
672 }
673 }
674
675 pub fn ibc_receiver_address(&self) -> Option<String> {
677 match self {
678 Self::Ibc(address) => Some(address.clone()),
679 _ => None,
680 }
681 }
682
683 pub fn address(&self) -> Option<Address> {
685 match self {
686 Self::Addr(x) => Some(x.clone()),
687 _ => None,
688 }
689 }
690
691 pub fn taddress(&self) -> TransparentAddress {
693 TransparentAddress(<[u8; 20]>::from(ripemd::Ripemd160::digest(
694 sha2::Sha256::digest(self.serialize_to_vec()),
695 )))
696 }
697}
698
699pub fn ibc_taddr(receiver: String) -> TransparentAddress {
701 TAddrData::Ibc(receiver).taddress()
702}
703
704pub fn addr_taddr(addr: Address) -> TransparentAddress {
706 TAddrData::Addr(addr).taddress()
707}
708
709#[derive(
711 Debug,
712 Clone,
713 BorshDeserialize,
714 BorshSerialize,
715 BorshDeserializer,
716 Hash,
717 Eq,
718 PartialEq,
719)]
720pub enum TransferTarget {
721 Address(Address),
723 PaymentAddress(PaymentAddress),
725 Ibc(String),
727}
728
729impl TransferTarget {
730 pub fn effective_address(&self) -> Address {
732 match self {
733 Self::Address(x) => x.clone(),
734 Self::PaymentAddress(_) => MASP,
737 Self::Ibc(_) => IBC,
740 }
741 }
742
743 pub fn payment_address(&self) -> Option<PaymentAddress> {
745 match self {
746 Self::PaymentAddress(address) => Some(*address),
747 _ => None,
748 }
749 }
750
751 pub fn address(&self) -> Option<Address> {
753 match self {
754 Self::Address(x) => Some(x.clone()),
755 _ => None,
756 }
757 }
758
759 pub fn t_addr_data(&self) -> Option<TAddrData> {
761 match self {
762 Self::Address(x) => Some(TAddrData::Addr(x.clone())),
763 Self::Ibc(x) => Some(TAddrData::Ibc(x.clone())),
764 _ => None,
765 }
766 }
767}
768
769impl Display for TransferTarget {
770 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
771 match self {
772 Self::Address(x) => x.fmt(f),
773 Self::PaymentAddress(address) => address.fmt(f),
774 Self::Ibc(x) => x.fmt(f),
775 }
776 }
777}
778
779#[allow(clippy::large_enum_variant)]
781#[derive(
782 Debug,
783 Clone,
784 Hash,
785 BorshSerialize,
786 BorshDeserialize,
787 BorshDeserializer,
788 PartialEq,
789 Eq,
790 PartialOrd,
791 Ord,
792)]
793pub enum BalanceOwner {
794 Address(Address),
796 FullViewingKey(ExtendedViewingKey),
798}
799
800impl BalanceOwner {
801 pub fn address(&self) -> Option<Address> {
803 match self {
804 Self::Address(x) => Some(x.clone()),
805 _ => None,
806 }
807 }
808
809 pub fn full_viewing_key(&self) -> Option<ExtendedViewingKey> {
811 match self {
812 Self::FullViewingKey(x) => Some(*x),
813 _ => None,
814 }
815 }
816}
817
818impl Display for BalanceOwner {
819 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
820 match self {
821 BalanceOwner::Address(addr) => addr.fmt(f),
822 BalanceOwner::FullViewingKey(fvk) => fvk.fmt(f),
823 }
824 }
825}
826
827#[allow(clippy::large_enum_variant)]
829#[derive(Debug, Clone)]
830pub enum MaspValue {
831 PaymentAddress(PaymentAddress),
833 ExtendedSpendingKey(ExtendedSpendingKey),
835 FullViewingKey(ExtendedViewingKey),
837}
838
839impl FromStr for MaspValue {
840 type Err = DecodeError;
841
842 fn from_str(s: &str) -> Result<Self, Self::Err> {
843 PaymentAddress::from_str(s)
846 .map(Self::PaymentAddress)
847 .or_else(|_err| {
848 ExtendedSpendingKey::from_str(s).map(Self::ExtendedSpendingKey)
849 })
850 .or_else(|_err| {
851 ExtendedViewingKey::from_str(s).map(Self::FullViewingKey)
852 })
853 }
854}
855
856#[cfg(test)]
857mod test {
858 use super::*;
859 use crate::address;
860
861 #[test]
862 fn test_extended_spending_key_serialize() {
863 let sk = ExtendedSpendingKey::from(
864 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
865 );
866 let serialized = serde_json::to_string(&sk).unwrap();
867 let deserialized: ExtendedSpendingKey =
868 serde_json::from_str(&serialized).unwrap();
869 assert_eq!(sk, deserialized);
870 }
871
872 #[test]
873 fn test_transfer_source_display() {
874 let addr = address::testing::established_address_1();
875 assert_eq!(addr.to_string(), TransferSource::Address(addr).to_string());
876
877 let sk = masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]);
878 assert_eq!(
879 ExtendedViewingKey::from(sk.to_viewing_key()).to_string(),
880 TransferSource::ExtendedKey(sk.into()).to_string()
881 );
882 }
883
884 #[test]
885 fn test_transfer_source_address() {
886 let addr =
887 TransferSource::Address(address::testing::established_address_1())
888 .address();
889 assert_eq!(addr.unwrap(), address::testing::established_address_1());
890
891 let addr = TransferSource::ExtendedKey(
892 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(),
893 )
894 .address();
895 assert!(addr.is_none());
896 }
897
898 #[test]
899 fn test_transfer_source_t_addr_data() {
900 let addr =
901 TransferSource::Address(address::testing::established_address_1())
902 .t_addr_data();
903 assert_eq!(
904 addr.unwrap(),
905 TAddrData::Addr(address::testing::established_address_1())
906 );
907
908 let addr = TransferSource::ExtendedKey(
909 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]).into(),
910 )
911 .address();
912 assert!(addr.is_none());
913 }
914
915 #[test]
916 fn test_transfer_source_effective_address() {
917 let source =
918 TransferSource::Address(address::testing::established_address_1());
919 assert_eq!(
920 source.effective_address(),
921 address::testing::established_address_1()
922 );
923
924 let sk = masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]);
925 let source = TransferSource::ExtendedKey(sk.into());
926 assert_eq!(source.effective_address(), MASP);
927 }
928
929 #[test]
930 fn test_pa_hash() {
931 let sk = ExtendedSpendingKey::from(
932 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
933 );
934 let (_diversifier, pa) = sk.0.default_address();
935 let pa = PaymentAddress::from(pa);
936
937 assert_eq!(pa.hash(), "F902054A142024BA72998F7AA6D5F7DB1700E489");
938 }
939
940 #[test]
941 fn test_taddrdata_address() {
942 let addr = TAddrData::Addr(address::testing::established_address_1())
943 .address();
944 assert_eq!(addr.unwrap(), address::testing::established_address_1());
945
946 let addr = TAddrData::Ibc(String::new()).address();
947 assert!(addr.is_none());
948 }
949
950 #[test]
951 fn test_taddrdata_ibc_receiver_address() {
952 let addr = TAddrData::Addr(address::testing::established_address_1())
953 .ibc_receiver_address();
954 assert!(addr.is_none());
955
956 let addr = TAddrData::Ibc("test".to_owned()).ibc_receiver_address();
957 assert_eq!(addr.unwrap(), "test");
958 }
959
960 #[test]
961 fn test_taddrdata_effective_address() {
962 let data = TAddrData::Addr(address::testing::established_address_1());
963 assert_eq!(
964 data.effective_address(),
965 address::testing::established_address_1()
966 );
967
968 let data = TAddrData::Ibc(String::new());
969 assert_eq!(data.effective_address(), IBC);
970 }
971
972 #[test]
973 fn test_transfer_target_effective_address() {
974 let target =
975 TransferTarget::Address(address::testing::established_address_1());
976 assert_eq!(
977 target.effective_address(),
978 address::testing::established_address_1()
979 );
980
981 let sk = ExtendedSpendingKey::from(
982 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
983 );
984 let (_diversifier, pa) = sk.0.default_address();
985 let pa = PaymentAddress::from(pa);
986 let target = TransferTarget::PaymentAddress(pa);
987 assert_eq!(target.effective_address(), MASP);
988
989 let target = TransferTarget::Ibc(String::new());
990 assert_eq!(target.effective_address(), IBC);
991 }
992
993 #[test]
994 fn test_transfer_target_address() {
995 let target =
996 TransferTarget::Address(address::testing::established_address_1())
997 .address();
998 assert_eq!(target.unwrap(), address::testing::established_address_1());
999
1000 let sk = ExtendedSpendingKey::from(
1001 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1002 );
1003 let (_diversifier, pa) = sk.0.default_address();
1004 let pa = PaymentAddress::from(pa);
1005 let target = TransferTarget::PaymentAddress(pa).address();
1006 assert!(target.is_none());
1007
1008 let target = TransferTarget::Ibc(String::new()).address();
1009 assert!(target.is_none());
1010 }
1011
1012 #[test]
1013 fn test_transfer_target_t_addr_data() {
1014 let target =
1015 TransferTarget::Address(address::testing::established_address_1())
1016 .t_addr_data();
1017 assert_eq!(
1018 target.unwrap(),
1019 TAddrData::Addr(address::testing::established_address_1())
1020 );
1021
1022 let sk = ExtendedSpendingKey::from(
1023 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1024 );
1025 let (_diversifier, pa) = sk.0.default_address();
1026 let pa = PaymentAddress::from(pa);
1027 let target = TransferTarget::PaymentAddress(pa).t_addr_data();
1028 assert!(target.is_none());
1029
1030 let target = TransferTarget::Ibc(String::new()).t_addr_data();
1031 assert_eq!(target.unwrap(), TAddrData::Ibc(String::new()));
1032 }
1033
1034 #[test]
1035 fn test_transfer_target_display() {
1036 let addr = address::testing::established_address_1();
1037
1038 let sk = ExtendedSpendingKey::from(
1039 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1040 );
1041 let (_diversifier, pa) = sk.0.default_address();
1042 let pa = PaymentAddress::from(pa);
1043
1044 const IBC_ADDR: &str = "noble18st0wqx84av8y6xdlss9d6m2nepyqwj6nfxxuv";
1045
1046 assert_eq!(addr.to_string(), TransferTarget::Address(addr).to_string());
1047
1048 assert_eq!(
1049 pa.to_string(),
1050 TransferTarget::PaymentAddress(pa).to_string()
1051 );
1052
1053 assert_eq!(
1054 IBC_ADDR.to_owned(),
1055 TransferTarget::Ibc(IBC_ADDR.to_owned()).to_string()
1056 );
1057 }
1058
1059 #[test]
1060 fn test_balance_owner_full_viewing_key() {
1061 let sk = ExtendedSpendingKey::from(
1062 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1063 );
1064 let vk = sk.to_viewing_key();
1065 assert_eq!(
1066 vk.clone(),
1067 BalanceOwner::FullViewingKey(vk).full_viewing_key().unwrap()
1068 );
1069
1070 let addr = address::testing::established_address_1();
1071 assert!(BalanceOwner::Address(addr).full_viewing_key().is_none());
1072 }
1073
1074 #[test]
1075 fn test_balance_owner_display() {
1076 let addr = address::testing::established_address_1();
1077
1078 let sk = ExtendedSpendingKey::from(
1079 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1080 );
1081 let vk = sk.to_viewing_key();
1082
1083 assert_eq!(addr.to_string(), BalanceOwner::Address(addr).to_string());
1084
1085 assert_eq!(
1086 vk.to_string(),
1087 BalanceOwner::FullViewingKey(vk).to_string()
1088 );
1089 }
1090
1091 #[test]
1092 fn test_balance_owner_borsh() {
1093 let addr = address::testing::established_address_1();
1094
1095 let owner = BalanceOwner::Address(addr);
1096 let serialized = owner.serialize_to_vec();
1097 let deserialized =
1098 BalanceOwner::try_from_slice(&serialized[..]).unwrap();
1099 assert_eq!(owner, deserialized);
1100
1101 let sk = ExtendedSpendingKey::from(
1102 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1103 );
1104 let vk = sk.to_viewing_key();
1105
1106 let owner = BalanceOwner::FullViewingKey(vk);
1107 let serialized = owner.serialize_to_vec();
1108 let deserialized =
1109 BalanceOwner::try_from_slice(&serialized[..]).unwrap();
1110 assert_eq!(owner, deserialized);
1111 }
1112
1113 #[test]
1114 fn test_transfer_target_borsh() {
1115 let addr = address::testing::established_address_1();
1116
1117 let target = TransferTarget::Address(addr);
1118 let serialized = target.serialize_to_vec();
1119 let deserialized =
1120 TransferTarget::try_from_slice(&serialized[..]).unwrap();
1121 assert_eq!(target, deserialized);
1122
1123 let sk = ExtendedSpendingKey::from(
1124 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1125 );
1126 let (_diversifier, pa) = sk.0.default_address();
1127 let pa = PaymentAddress::from(pa);
1128
1129 let target = TransferTarget::PaymentAddress(pa);
1130 let serialized = target.serialize_to_vec();
1131 let deserialized =
1132 TransferTarget::try_from_slice(&serialized[..]).unwrap();
1133 assert_eq!(target, deserialized);
1134
1135 const IBC_ADDR: &str = "noble18st0wqx84av8y6xdlss9d6m2nepyqwj6nfxxuv";
1136
1137 let target = TransferTarget::Ibc(IBC_ADDR.to_owned());
1138 let serialized = target.serialize_to_vec();
1139 let deserialized =
1140 TransferTarget::try_from_slice(&serialized[..]).unwrap();
1141 assert_eq!(target, deserialized);
1142 }
1143
1144 #[test]
1145 fn test_masp_tx_id_display() {
1146 let tx_id = MaspTxId::from(TxIdInner::from_bytes([
1147 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1148 0, 0, 0, 0, 0, 0, 0, 0, 12, 11,
1149 ]));
1150 assert_eq!(
1151 tx_id.to_string(),
1152 "0b0c00000000000000000000000000000000000000000000000000000000000a"
1153 );
1154 }
1155
1156 #[test]
1157 fn test_masp_tx_id_basics() {
1158 let tx_id = MaspTxId::from(TxIdInner::from_bytes([
1159 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1161 ]));
1162 let tx_id_str = serde_json::to_string(&tx_id).unwrap();
1163 let decoded: MaspTxId = serde_json::from_str(&tx_id_str).unwrap();
1164 assert_eq!(tx_id, decoded);
1165 }
1166
1167 #[test]
1168 fn test_masp_epoch_basics() {
1169 let epoch = MaspEpoch::new(123);
1170 let epoch_str = epoch.to_string();
1171 assert_eq!(&epoch_str, "123");
1172 let decoded = MaspEpoch::from_str(&epoch_str).unwrap();
1173 assert_eq!(epoch, decoded);
1174 }
1175
1176 #[test]
1177 fn test_masp_asset_data_basics() {
1178 let data = AssetData {
1179 token: address::testing::nam(),
1180 denom: Denomination(6),
1181 position: MaspDigitPos::One,
1182 epoch: None,
1183 };
1184
1185 let data = data.undate();
1186 assert!(data.epoch.is_none());
1187
1188 let epoch_0 = MaspEpoch::new(3);
1189 let mut data = data.redate(epoch_0);
1190 assert!(data.epoch.is_none());
1191 data.epoch = Some(epoch_0);
1192
1193 let epoch_1 = MaspEpoch::new(5);
1194 let data = data.redate(epoch_1);
1195 assert_eq!(data.epoch, Some(epoch_1));
1196 }
1197
1198 #[test]
1199 fn test_masp_keys_basics() {
1200 let sk = ExtendedSpendingKey::from(
1201 masp_primitives::zip32::ExtendedSpendingKey::master(&[0_u8]),
1202 );
1203 string_encoding::testing::test_string_formatting(&sk);
1204
1205 let vk = sk.to_viewing_key();
1206 string_encoding::testing::test_string_formatting(&vk);
1207
1208 let (_diversifier, pa) = sk.0.default_address();
1209 let pa = PaymentAddress::from(pa);
1210 string_encoding::testing::test_string_formatting(&pa);
1211 }
1212}