pallas_addresses/
lib.rs

1//! Interact with Cardano addresses of any type
2//!
3//! This module contains utilities to decode / encode Cardano addresses from /
4//! to different formats. The entry point to most of the methods is the
5//! [Address] enum, which holds the decoded values of either a Byron, Shelley or
6//! Stake address.
7//!
8//! For more information regarding Cardano addresses and their formats, please refer to [CIP-19](https://cips.cardano.org/cips/cip19/).
9
10pub mod byron;
11pub mod varuint;
12
13use std::{fmt::Display, io::Cursor, str::FromStr};
14
15use pallas_crypto::hash::Hash;
16use thiserror::Error;
17
18#[derive(Error, Debug)]
19pub enum Error {
20    #[error("error converting from/to bech32 {0}")]
21    BadBech32(bech32::Error),
22
23    #[error("error decoding base58 value")]
24    BadBase58(base58::FromBase58Error),
25
26    #[error("error decoding hex value")]
27    BadHex,
28
29    #[error("unknown or bad string format for address {0}")]
30    UnknownStringFormat(String),
31
32    #[error("address header not found")]
33    MissingHeader,
34
35    #[error("address header is invalid {0:08b}")]
36    InvalidHeader(u8),
37
38    #[error("invalid operation for Byron address")]
39    InvalidForByron,
40
41    #[error("invalid operation for address content")]
42    InvalidForContent,
43
44    #[error("invalid CBOR for Byron address {0}")]
45    InvalidByronCbor(pallas_codec::minicbor::decode::Error),
46
47    #[error("unkown hrp for network {0:08b}")]
48    UnknownNetworkHrp(u8),
49
50    #[error("invalid hash size {0}")]
51    InvalidHashSize(usize),
52
53    #[error("invalid address length {0}")]
54    InvalidAddressLength(usize),
55
56    #[error("invalid pointer data")]
57    InvalidPointerData,
58
59    #[error("variable-length uint error: {0}")]
60    VarUintError(varuint::Error),
61}
62
63pub type PaymentKeyHash = Hash<28>;
64pub type StakeKeyHash = Hash<28>;
65pub type ScriptHash = Hash<28>;
66
67pub type Slot = u64;
68pub type TxIdx = u64;
69pub type CertIdx = u64;
70
71/// An on-chain pointer to a stake key
72#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct Pointer(Slot, TxIdx, CertIdx);
74
75fn slice_to_hash(slice: &[u8]) -> Result<Hash<28>, Error> {
76    if slice.len() == 28 {
77        let mut sized = [0u8; 28];
78        sized.copy_from_slice(slice);
79        Ok(sized.into())
80    } else {
81        Err(Error::InvalidHashSize(slice.len()))
82    }
83}
84
85impl Pointer {
86    pub fn new(slot: Slot, tx_idx: TxIdx, cert_idx: CertIdx) -> Self {
87        Pointer(slot, tx_idx, cert_idx)
88    }
89
90    pub fn parse(bytes: &[u8]) -> Result<Self, Error> {
91        let mut cursor = Cursor::new(bytes);
92        let a = varuint::read(&mut cursor).map_err(Error::VarUintError)?;
93        let b = varuint::read(&mut cursor).map_err(Error::VarUintError)?;
94        let c = varuint::read(&mut cursor).map_err(Error::VarUintError)?;
95
96        Ok(Pointer(a, b, c))
97    }
98
99    pub fn to_vec(&self) -> Vec<u8> {
100        let mut cursor = Cursor::new(vec![]);
101        varuint::write(&mut cursor, self.0);
102        varuint::write(&mut cursor, self.1);
103        varuint::write(&mut cursor, self.2);
104
105        cursor.into_inner()
106    }
107
108    pub fn slot(&self) -> u64 {
109        self.0
110    }
111
112    pub fn tx_idx(&self) -> u64 {
113        self.1
114    }
115
116    pub fn cert_idx(&self) -> u64 {
117        self.2
118    }
119}
120
121/// The payment part of a Shelley address
122#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
123pub enum ShelleyPaymentPart {
124    Key(PaymentKeyHash),
125    Script(ScriptHash),
126}
127
128impl ShelleyPaymentPart {
129    pub fn key_hash(hash: Hash<28>) -> Self {
130        Self::Key(hash)
131    }
132
133    pub fn script_hash(hash: Hash<28>) -> Self {
134        Self::Script(hash)
135    }
136
137    /// Get a reference to the inner hash of this address part
138    pub fn as_hash(&self) -> &Hash<28> {
139        match self {
140            Self::Key(x) => x,
141            Self::Script(x) => x,
142        }
143    }
144
145    /// Encodes this address as a sequence of bytes
146    pub fn to_vec(&self) -> Vec<u8> {
147        match self {
148            Self::Key(x) => x.to_vec(),
149            Self::Script(x) => x.to_vec(),
150        }
151    }
152
153    pub fn to_hex(&self) -> String {
154        let bytes = self.to_vec();
155        hex::encode(bytes)
156    }
157
158    pub fn to_bech32(&self) -> Result<String, Error> {
159        let hrp = match self {
160            Self::Key(_) => "addr_vkh",
161            Self::Script(_) => "addr_shared_vkh",
162        };
163        let bytes = self.to_vec();
164        encode_bech32(&bytes, hrp)
165    }
166
167    /// Indicates if this is the hash of a script
168    pub fn is_script(&self) -> bool {
169        matches!(self, Self::Script(_))
170    }
171}
172
173/// The delegation part of a Shelley address
174#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
175pub enum ShelleyDelegationPart {
176    Key(StakeKeyHash),
177    Script(ScriptHash),
178    Pointer(Pointer),
179    Null,
180}
181
182impl ShelleyDelegationPart {
183    pub fn key_hash(hash: Hash<28>) -> Self {
184        Self::Key(hash)
185    }
186
187    pub fn script_hash(hash: Hash<28>) -> Self {
188        Self::Script(hash)
189    }
190
191    pub fn from_pointer(bytes: &[u8]) -> Result<Self, Error> {
192        let pointer = Pointer::parse(bytes)?;
193        Ok(Self::Pointer(pointer))
194    }
195
196    /// Get a reference to the inner hash of this address part
197    pub fn as_hash(&self) -> Option<&Hash<28>> {
198        match self {
199            Self::Key(x) => Some(x),
200            Self::Script(x) => Some(x),
201            Self::Pointer(_) => None,
202            Self::Null => None,
203        }
204    }
205
206    pub fn to_vec(&self) -> Vec<u8> {
207        match self {
208            Self::Key(x) => x.to_vec(),
209            Self::Script(x) => x.to_vec(),
210            Self::Pointer(x) => x.to_vec(),
211            Self::Null => vec![],
212        }
213    }
214
215    pub fn to_hex(&self) -> String {
216        let bytes = self.to_vec();
217        hex::encode(bytes)
218    }
219
220    pub fn to_bech32(&self) -> Result<String, Error> {
221        let hrp = match self {
222            Self::Key(_) => "stake_vkh",
223            Self::Script(_) => "stake_shared_vkh",
224            _ => return Err(Error::InvalidForContent),
225        };
226
227        let bytes = self.to_vec();
228        encode_bech32(&bytes, hrp)
229    }
230
231    pub fn is_script(&self) -> bool {
232        matches!(self, ShelleyDelegationPart::Script(_))
233    }
234}
235
236impl StakePayload {
237    fn stake_key(bytes: &[u8]) -> Result<Self, Error> {
238        slice_to_hash(bytes).map(StakePayload::Stake)
239    }
240
241    fn script(bytes: &[u8]) -> Result<Self, Error> {
242        slice_to_hash(bytes).map(StakePayload::Script)
243    }
244
245    pub fn is_script(&self) -> bool {
246        matches!(self, StakePayload::Script(_))
247    }
248
249    /// Get a reference to the inner hash of this address part
250    pub fn as_hash(&self) -> &Hash<28> {
251        match self {
252            StakePayload::Stake(x) => x,
253            StakePayload::Script(x) => x,
254        }
255    }
256}
257
258/// The network tag of an address
259#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)]
260pub enum Network {
261    Testnet,
262    Mainnet,
263    Other(u8),
264}
265
266impl From<u8> for Network {
267    fn from(id: u8) -> Self {
268        match id {
269            0 => Network::Testnet,
270            1 => Network::Mainnet,
271            x => Network::Other(x),
272        }
273    }
274}
275
276/// A decoded Shelley address
277#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
278pub struct ShelleyAddress(Network, ShelleyPaymentPart, ShelleyDelegationPart);
279
280/// The payload of a Stake address
281#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
282pub enum StakePayload {
283    Stake(StakeKeyHash),
284    Script(ScriptHash),
285}
286
287/// A decoded Stake address
288#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
289pub struct StakeAddress(Network, StakePayload);
290
291pub use byron::ByronAddress;
292
293/// A decoded Cardano address of any type
294#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
295pub enum Address {
296    Byron(ByronAddress),
297    Shelley(ShelleyAddress),
298    Stake(StakeAddress),
299}
300
301fn encode_bech32(addr: &[u8], hrp: &str) -> Result<String, Error> {
302    let base32 = bech32::ToBase32::to_base32(&addr);
303    bech32::encode(hrp, base32, bech32::Variant::Bech32).map_err(Error::BadBech32)
304}
305
306fn decode_bech32(bech32: &str) -> Result<(String, Vec<u8>), Error> {
307    let (hrp, addr, _) = bech32::decode(bech32).map_err(Error::BadBech32)?;
308    let base10 = bech32::FromBase32::from_base32(&addr).map_err(Error::BadBech32)?;
309    Ok((hrp, base10))
310}
311
312fn parse_network(header: u8) -> Network {
313    let masked = header & 0b0000_1111;
314
315    match masked {
316        0b_0000_0000 => Network::Testnet,
317        0b_0000_0001 => Network::Mainnet,
318        _ => Network::Other(masked),
319    }
320}
321
322macro_rules! parse_shelley_fn {
323    ($name:tt, $payment:tt, pointer) => {
324        fn $name(header: u8, payload: &[u8]) -> Result<Address, Error> {
325            if payload.len() < 29 {
326                return Err(Error::InvalidAddressLength(payload.len()));
327            }
328
329            let net = parse_network(header);
330            let h1 = slice_to_hash(&payload[0..=27])?;
331            let p1 = ShelleyPaymentPart::$payment(h1);
332            let p2 = ShelleyDelegationPart::from_pointer(&payload[28..])?;
333            let addr = ShelleyAddress(net, p1, p2);
334
335            Ok(addr.into())
336        }
337    };
338    ($name:tt, $payment:tt, $delegation:tt) => {
339        fn $name(header: u8, payload: &[u8]) -> Result<Address, Error> {
340            if payload.len() < 56 {
341                return Err(Error::InvalidAddressLength(payload.len()));
342            }
343
344            let net = parse_network(header);
345            let h1 = slice_to_hash(&payload[0..=27])?;
346            let p1 = ShelleyPaymentPart::$payment(h1);
347            let h2 = slice_to_hash(&payload[28..=55])?;
348            let p2 = ShelleyDelegationPart::$delegation(h2);
349            let addr = ShelleyAddress(net, p1, p2);
350
351            Ok(addr.into())
352        }
353    };
354    ($name:tt, $payment:tt) => {
355        fn $name(header: u8, payload: &[u8]) -> Result<Address, Error> {
356            if payload.len() < 28 {
357                return Err(Error::InvalidAddressLength(payload.len()));
358            }
359
360            let net = parse_network(header);
361            let h1 = slice_to_hash(&payload[0..=27])?;
362            let p1 = ShelleyPaymentPart::$payment(h1);
363            let addr = ShelleyAddress(net, p1, ShelleyDelegationPart::Null);
364
365            Ok(addr.into())
366        }
367    };
368}
369
370macro_rules! parse_stake_fn {
371    ($name:tt, $type:tt) => {
372        fn $name(header: u8, payload: &[u8]) -> Result<Address, Error> {
373            if payload.len() < 28 {
374                return Err(Error::InvalidAddressLength(payload.len()));
375            }
376
377            let net = parse_network(header);
378            let p1 = StakePayload::$type(&payload[0..=27])?;
379            let addr = StakeAddress(net, p1);
380
381            Ok(addr.into())
382        }
383    };
384}
385
386// types 0-7 are Shelley addresses
387parse_shelley_fn!(parse_type_0, key_hash, key_hash);
388parse_shelley_fn!(parse_type_1, script_hash, key_hash);
389parse_shelley_fn!(parse_type_2, key_hash, script_hash);
390parse_shelley_fn!(parse_type_3, script_hash, script_hash);
391parse_shelley_fn!(parse_type_4, key_hash, pointer);
392parse_shelley_fn!(parse_type_5, script_hash, pointer);
393parse_shelley_fn!(parse_type_6, key_hash);
394parse_shelley_fn!(parse_type_7, script_hash);
395
396// type 8 (1000) are Byron addresses
397fn parse_type_8(header: u8, payload: &[u8]) -> Result<Address, Error> {
398    let vec = [&[header], payload].concat();
399    let inner = pallas_codec::minicbor::decode(&vec).map_err(Error::InvalidByronCbor)?;
400    Ok(Address::Byron(inner))
401}
402
403// types 14-15 are Stake addresses
404parse_stake_fn!(parse_type_14, stake_key);
405parse_stake_fn!(parse_type_15, script);
406
407fn bytes_to_address(bytes: &[u8]) -> Result<Address, Error> {
408    let header = *bytes.first().ok_or(Error::MissingHeader)?;
409    let payload = &bytes[1..];
410
411    match header & 0b1111_0000 {
412        0b0000_0000 => parse_type_0(header, payload),
413        0b0001_0000 => parse_type_1(header, payload),
414        0b0010_0000 => parse_type_2(header, payload),
415        0b0011_0000 => parse_type_3(header, payload),
416        0b0100_0000 => parse_type_4(header, payload),
417        0b0101_0000 => parse_type_5(header, payload),
418        0b0110_0000 => parse_type_6(header, payload),
419        0b0111_0000 => parse_type_7(header, payload),
420        0b1000_0000 => parse_type_8(header, payload),
421        0b1110_0000 => parse_type_14(header, payload),
422        0b1111_0000 => parse_type_15(header, payload),
423        _ => Err(Error::InvalidHeader(header)),
424    }
425}
426
427fn bech32_to_address(bech32: &str) -> Result<Address, Error> {
428    let (_, bytes) = decode_bech32(bech32)?;
429    bytes_to_address(&bytes)
430}
431
432impl Network {
433    pub fn is_mainnet(&self) -> bool {
434        matches!(self, Network::Mainnet)
435    }
436
437    pub fn value(&self) -> u8 {
438        match self {
439            Network::Testnet => 0,
440            Network::Mainnet => 1,
441            Network::Other(x) => *x,
442        }
443    }
444}
445
446impl ShelleyAddress {
447    pub fn new(
448        network: Network,
449        payment: ShelleyPaymentPart,
450        delegation: ShelleyDelegationPart,
451    ) -> Self {
452        Self(network, payment, delegation)
453    }
454
455    /// Gets the network assoaciated with this address
456    pub fn network(&self) -> Network {
457        self.0
458    }
459
460    /// Gets a numeric id describing the type of the address
461    pub fn typeid(&self) -> u8 {
462        match (&self.1, &self.2) {
463            (ShelleyPaymentPart::Key(_), ShelleyDelegationPart::Key(_)) => 0b0000,
464            (ShelleyPaymentPart::Script(_), ShelleyDelegationPart::Key(_)) => 0b0001,
465            (ShelleyPaymentPart::Key(_), ShelleyDelegationPart::Script(_)) => 0b0010,
466            (ShelleyPaymentPart::Script(_), ShelleyDelegationPart::Script(_)) => 0b0011,
467            (ShelleyPaymentPart::Key(_), ShelleyDelegationPart::Pointer(_)) => 0b0100,
468            (ShelleyPaymentPart::Script(_), ShelleyDelegationPart::Pointer(_)) => 0b0101,
469            (ShelleyPaymentPart::Key(_), ShelleyDelegationPart::Null) => 0b0110,
470            (ShelleyPaymentPart::Script(_), ShelleyDelegationPart::Null) => 0b0111,
471        }
472    }
473
474    pub fn to_header(&self) -> u8 {
475        let type_id = self.typeid();
476        let type_id = type_id << 4;
477        let network = self.0.value();
478
479        type_id | network
480    }
481
482    pub fn payment(&self) -> &ShelleyPaymentPart {
483        &self.1
484    }
485
486    pub fn delegation(&self) -> &ShelleyDelegationPart {
487        &self.2
488    }
489
490    /// Gets the bech32 human-readable-part for this address
491    pub fn hrp(&self) -> Result<&'static str, Error> {
492        match &self.0 {
493            Network::Testnet => Ok("addr_test"),
494            Network::Mainnet => Ok("addr"),
495            Network::Other(x) => Err(Error::UnknownNetworkHrp(*x)),
496        }
497    }
498
499    pub fn to_vec(&self) -> Vec<u8> {
500        let header = self.to_header();
501        let payment = self.1.to_vec();
502        let delegation = self.2.to_vec();
503
504        [&[header], payment.as_slice(), delegation.as_slice()].concat()
505    }
506
507    pub fn to_hex(&self) -> String {
508        let bytes = self.to_vec();
509        hex::encode(bytes)
510    }
511
512    pub fn to_bech32(&self) -> Result<String, Error> {
513        let hrp = self.hrp()?;
514        let bytes = self.to_vec();
515        encode_bech32(&bytes, hrp)
516    }
517
518    /// Indicates if either the payment or delegation part is a script
519    pub fn has_script(&self) -> bool {
520        self.payment().is_script() || self.delegation().is_script()
521    }
522}
523
524impl TryFrom<ShelleyAddress> for StakeAddress {
525    type Error = Error;
526
527    fn try_from(value: ShelleyAddress) -> Result<Self, Self::Error> {
528        let payload = match value.delegation() {
529            ShelleyDelegationPart::Key(h) => StakePayload::Stake(*h),
530            ShelleyDelegationPart::Script(h) => StakePayload::Script(*h),
531            _ => return Err(Error::InvalidForContent),
532        };
533
534        Ok(StakeAddress(value.network(), payload))
535    }
536}
537
538impl AsRef<[u8]> for StakePayload {
539    fn as_ref(&self) -> &[u8] {
540        match self {
541            Self::Stake(x) => x.as_ref(),
542            Self::Script(x) => x.as_ref(),
543        }
544    }
545}
546
547impl StakeAddress {
548    /// Gets the network assoaciated with this address
549    pub fn network(&self) -> Network {
550        self.0
551    }
552
553    /// Gets a numeric id describing the type of the address
554    pub fn typeid(&self) -> u8 {
555        match &self.1 {
556            StakePayload::Stake(_) => 0b1110,
557            StakePayload::Script(_) => 0b1111,
558        }
559    }
560
561    /// Builds the header for this address
562    pub fn to_header(&self) -> u8 {
563        let type_id = self.typeid();
564        let type_id = type_id << 4;
565        let network = self.0.value();
566
567        type_id | network
568    }
569
570    /// Gets the payload of this address
571    pub fn payload(&self) -> &StakePayload {
572        &self.1
573    }
574
575    /// Gets the bech32 human-readable-part for this address
576    pub fn hrp(&self) -> Result<&'static str, Error> {
577        match &self.0 {
578            Network::Testnet => Ok("stake_test"),
579            Network::Mainnet => Ok("stake"),
580            Network::Other(x) => Err(Error::UnknownNetworkHrp(*x)),
581        }
582    }
583
584    pub fn to_vec(&self) -> Vec<u8> {
585        let header = self.to_header();
586
587        [&[header], self.1.as_ref()].concat()
588    }
589
590    pub fn to_hex(&self) -> String {
591        let bytes = self.to_vec();
592        hex::encode(bytes)
593    }
594
595    pub fn to_bech32(&self) -> Result<String, Error> {
596        let hrp = self.hrp()?;
597        let bytes = self.to_vec();
598        encode_bech32(&bytes, hrp)
599    }
600
601    pub fn is_script(&self) -> bool {
602        self.payload().is_script()
603    }
604}
605
606impl Address {
607    /// Tries to encode an Address into a bech32 string
608    pub fn to_bech32(&self) -> Result<String, Error> {
609        match self {
610            Address::Byron(_) => Err(Error::InvalidForByron),
611            Address::Shelley(x) => x.to_bech32(),
612            Address::Stake(x) => x.to_bech32(),
613        }
614    }
615
616    /// Tries to parse a bech32 value into an Address
617    pub fn from_bech32(bech32: &str) -> Result<Self, Error> {
618        bech32_to_address(bech32)
619    }
620
621    // Tries to decode the raw bytes of an address
622    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
623        bytes_to_address(bytes)
624    }
625
626    // Tries to parse a hex value into an Address
627    pub fn from_hex(bytes: &str) -> Result<Self, Error> {
628        let bytes = hex::decode(bytes).map_err(|_| Error::BadHex)?;
629        bytes_to_address(&bytes)
630    }
631
632    /// Gets the network assoaciated with this address
633    pub fn network(&self) -> Option<Network> {
634        match self {
635            Address::Byron(_) => None,
636            Address::Shelley(x) => Some(x.network()),
637            Address::Stake(x) => Some(x.network()),
638        }
639    }
640
641    /// Gets a numeric id describing the type of the address
642    pub fn typeid(&self) -> u8 {
643        match self {
644            Address::Byron(x) => x.typeid(),
645            Address::Shelley(x) => x.typeid(),
646            Address::Stake(x) => x.typeid(),
647        }
648    }
649
650    /// Gets the bech32 human-readable-part for this address
651    pub fn hrp(&self) -> Result<&'static str, Error> {
652        match self {
653            Address::Byron(_) => Err(Error::InvalidForByron),
654            Address::Shelley(x) => x.hrp(),
655            Address::Stake(x) => x.hrp(),
656        }
657    }
658
659    /// Indicates if this is address includes a script hash
660    pub fn has_script(&self) -> bool {
661        match self {
662            Address::Byron(_) => false,
663            Address::Shelley(x) => x.has_script(),
664            Address::Stake(x) => x.is_script(),
665        }
666    }
667
668    /// Indicates if this is an enterpise address
669    pub fn is_enterprise(&self) -> bool {
670        match self {
671            Address::Shelley(x) => matches!(x.delegation(), ShelleyDelegationPart::Null),
672            _ => false,
673        }
674    }
675
676    pub fn to_vec(&self) -> Vec<u8> {
677        match self {
678            Address::Byron(x) => x.to_vec(),
679            Address::Shelley(x) => x.to_vec(),
680            Address::Stake(x) => x.to_vec(),
681        }
682    }
683
684    pub fn to_hex(&self) -> String {
685        match self {
686            Address::Byron(x) => x.to_hex(),
687            Address::Shelley(x) => x.to_hex(),
688            Address::Stake(x) => x.to_hex(),
689        }
690    }
691}
692
693impl Display for Address {
694    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
695        match self {
696            Address::Byron(x) => f.write_str(&x.to_base58()),
697            Address::Shelley(x) => f.write_str(&x.to_bech32().unwrap_or_else(|_| x.to_hex())),
698            Address::Stake(x) => f.write_str(&x.to_bech32().unwrap_or_else(|_| x.to_hex())),
699        }
700    }
701}
702
703impl FromStr for Address {
704    type Err = Error;
705
706    fn from_str(s: &str) -> Result<Self, Self::Err> {
707        if let Ok(x) = Address::from_bech32(s) {
708            return Ok(x);
709        }
710
711        if let Ok(x) = ByronAddress::from_base58(s) {
712            return Ok(x.into());
713        }
714
715        if let Ok(x) = Address::from_hex(s) {
716            return Ok(x);
717        }
718
719        Err(Error::UnknownStringFormat(s.to_owned()))
720    }
721}
722
723impl TryFrom<&[u8]> for Address {
724    type Error = Error;
725
726    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
727        bytes_to_address(value)
728    }
729}
730
731impl From<ByronAddress> for Address {
732    fn from(addr: ByronAddress) -> Self {
733        Address::Byron(addr)
734    }
735}
736
737impl From<ShelleyAddress> for Address {
738    fn from(addr: ShelleyAddress) -> Self {
739        Address::Shelley(addr)
740    }
741}
742
743impl From<StakeAddress> for Address {
744    fn from(addr: StakeAddress) -> Self {
745        Address::Stake(addr)
746    }
747}
748
749#[cfg(test)]
750mod tests {
751    use std::str::FromStr;
752
753    use super::*;
754
755    const MAINNET_TEST_VECTORS: &[(&str, u8)] = &[
756        ("addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x", 0u8),
757        ("addr1z8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gten0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs9yc0hh", 1u8),
758        ("addr1yx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzerkr0vd4msrxnuwnccdxlhdjar77j6lg0wypcc9uar5d2shs2z78ve", 2u8),
759        ("addr1x8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gt7r0vd4msrxnuwnccdxlhdjar77j6lg0wypcc9uar5d2shskhj42g", 3u8),
760        ("addr1gx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer5pnz75xxcrzqf96k", 4u8),
761        ("addr128phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtupnz75xxcrtw79hu", 5u8),
762        ("addr1vx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzers66hrl8", 6u8),
763        ("addr1w8phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcyjy7wx", 7u8),
764        ("stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw", 14u8),
765        ("stake178phkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcccycj5", 15u8),
766        ("37btjrVyb4KDXBNC4haBVPCrro8AQPHwvCMp3RFhhSVWwfFmZ6wwzSK6JK1hY6wHNmtrpTf1kdbva8TCneM2YsiXT7mrzT21EacHnPpz5YyUdj64na", 8u8),
767    ];
768
769    const PAYMENT_PUBLIC_KEY: &str =
770        "addr_vk1w0l2sr2zgfm26ztc6nl9xy8ghsk5sh6ldwemlpmp9xylzy4dtf7st80zhd";
771    const STAKE_PUBLIC_KEY: &str =
772        "stake_vk1px4j0r2fk7ux5p23shz8f3y5y2qam7s954rgf3lg5merqcj6aetsft99wu";
773    const SCRIPT_HASH: &str = "script1cda3khwqv60360rp5m7akt50m6ttapacs8rqhn5w342z7r35m37";
774
775    fn hash_vector_key(key: &str) -> Hash<28> {
776        let (_, x) = decode_bech32(key).unwrap();
777        pallas_crypto::hash::Hasher::<224>::hash(&x)
778    }
779
780    #[test]
781    fn roundtrip_bech32() {
782        for vector in MAINNET_TEST_VECTORS {
783            let original = vector.0;
784            match Address::from_str(original) {
785                Ok(Address::Byron(_)) => (),
786                Ok(addr) => {
787                    let ours = addr.to_bech32().unwrap();
788                    assert_eq!(original, ours);
789                }
790                _ => panic!("should be able to decode from bech32"),
791            }
792        }
793    }
794
795    #[test]
796    fn roundtrip_string() {
797        for vector in MAINNET_TEST_VECTORS {
798            let original = vector.0;
799            let addr = Address::from_str(original).unwrap();
800            let ours = addr.to_string();
801            assert_eq!(original, ours);
802        }
803    }
804
805    #[test]
806    fn typeid_matches() {
807        for vector in MAINNET_TEST_VECTORS {
808            let original = vector.0;
809            let addr = Address::from_str(original).unwrap();
810            assert_eq!(addr.typeid(), vector.1);
811        }
812    }
813
814    #[test]
815    fn network_matches() {
816        for vector in MAINNET_TEST_VECTORS {
817            let original = vector.0;
818            let addr = Address::from_str(original).unwrap();
819
820            match addr {
821                Address::Byron(_) => assert!(addr.network().is_none()),
822                _ => assert!(matches!(addr.network(), Some(Network::Mainnet))),
823            }
824        }
825    }
826
827    #[test]
828    fn payload_matches() {
829        for vector in MAINNET_TEST_VECTORS {
830            let original = vector.0;
831            let addr = Address::from_str(original).unwrap();
832
833            match addr {
834                Address::Shelley(x) => {
835                    match x.payment() {
836                        ShelleyPaymentPart::Key(hash) => {
837                            let expected = &hash_vector_key(PAYMENT_PUBLIC_KEY);
838                            assert_eq!(hash, expected);
839                        }
840                        ShelleyPaymentPart::Script(hash) => {
841                            let (_, expected) = &decode_bech32(SCRIPT_HASH).unwrap();
842                            let expected = &Hash::<28>::from_str(&hex::encode(expected)).unwrap();
843                            assert_eq!(hash, expected);
844                        }
845                    };
846
847                    match x.delegation() {
848                        ShelleyDelegationPart::Key(hash) => {
849                            let expected = &hash_vector_key(STAKE_PUBLIC_KEY);
850                            assert_eq!(hash, expected);
851                        }
852                        ShelleyDelegationPart::Script(hash) => {
853                            let (_, expected) = &decode_bech32(SCRIPT_HASH).unwrap();
854                            let expected = &Hash::<28>::from_str(&hex::encode(expected)).unwrap();
855                            assert_eq!(hash, expected);
856                        }
857                        ShelleyDelegationPart::Pointer(ptr) => {
858                            assert_eq!(ptr.slot(), 2498243);
859                            assert_eq!(ptr.tx_idx(), 27);
860                            assert_eq!(ptr.cert_idx(), 3);
861                        }
862                        _ => (),
863                    };
864                }
865                Address::Stake(x) => match x.payload() {
866                    StakePayload::Stake(hash) => {
867                        let expected = &hash_vector_key(STAKE_PUBLIC_KEY);
868                        assert_eq!(hash, expected);
869                    }
870                    StakePayload::Script(hash) => {
871                        let (_, expected) = &decode_bech32(SCRIPT_HASH).unwrap();
872                        let expected = &Hash::<28>::from_str(&hex::encode(expected)).unwrap();
873                        assert_eq!(hash, expected);
874                    }
875                },
876                Address::Byron(_) => {
877                    // byron has it's own payload tests
878                }
879            };
880        }
881    }
882
883    #[test]
884    fn construct_from_parts() {
885        let payment_hash = hash_vector_key(PAYMENT_PUBLIC_KEY);
886        let delegation_hash = hash_vector_key(STAKE_PUBLIC_KEY);
887
888        let addr: Address = ShelleyAddress::new(
889            Network::Mainnet,
890            ShelleyPaymentPart::key_hash(payment_hash),
891            ShelleyDelegationPart::key_hash(delegation_hash),
892        )
893        .into();
894
895        assert_eq!(addr.to_bech32().unwrap(), MAINNET_TEST_VECTORS[0].0);
896    }
897
898    #[test]
899    fn test_minted_invalid_pointed_address() {
900        let addr = Address::from_hex("40C19D7D05E90EEB6394B53313FE79D47077DE33068C6B813BBE5C9D5681FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F81FFFFFFFFFFFFFFFF7F81FFFFFFFFFFFFFFFF7F");
901        assert!(matches!(addr, Ok(Address::Shelley(_))));
902    }
903
904    #[test]
905    fn test_shelley_into_stake() {
906        let addr = Address::from_bech32("addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x").unwrap();
907
908        match addr {
909            Address::Shelley(shelley_addr) => {
910                let stake_addr: StakeAddress = shelley_addr.clone().try_into().unwrap();
911                assert_eq!(stake_addr.network(), shelley_addr.network());
912
913                let stake_hash = stake_addr.payload().as_hash();
914                let shelley_hash = shelley_addr.delegation().as_hash().unwrap();
915                assert_eq!(stake_hash, shelley_hash);
916            }
917            _ => panic!(),
918        }
919    }
920
921    #[test]
922    fn test_minted_extra_bytes_base_address() {
923        let addr = Address::from_hex("015bad085057ac10ecc7060f7ac41edd6f63068d8963ef7d86ca58669e5ecf2d283418a60be5a848a2380eb721000da1e0bbf39733134beca4cb57afb0b35fc89c63061c9914e055001a518c7516");
924        assert!(matches!(addr, Ok(Address::Shelley(_))));
925    }
926}