bitcoincash_addr/
lib.rs

1//! # Bitcoin Cash Address Library
2//!
3//! A simple library providing an `Address` struct enabling
4//! encoding/decoding of Bitcoin Cash addresses.
5//!
6//! ```
7//! use bitcoincash_addr::{Address, Network, Scheme};
8//!
9//! fn main() {
10//!     // Decode base58 address
11//!     let legacy_addr = "1NM2HFXin4cEQRBLjkNZAS98qLX9JKzjKn";
12//!     let mut addr = Address::decode(legacy_addr).unwrap();
13//!
14//!     // Change the base58 address to a test network cashaddr
15//!     addr.network = Network::Test;
16//!     addr.scheme = Scheme::CashAddr;
17//!
18//!     // Encode cashaddr
19//!     let cashaddr_str = addr.encode().unwrap();
20//!
21//!     // bchtest:qr4zgpuznfg923ntyauyeh5v7333v72xhum2dsdgfh
22//!     println!("{}", cashaddr_str);
23//! }
24//!
25//! ```
26//!
27
28pub mod base58;
29pub mod cashaddr;
30
31pub use base58::Base58Codec;
32pub use cashaddr::CashAddrCodec;
33
34/// Bitcoin Networks.
35#[derive(PartialEq, Eq, Clone, Debug, Hash)]
36pub enum Network {
37    /// Main network.
38    Main,
39    /// Test network.
40    Test,
41    /// Regression test network.
42    Regtest,
43}
44
45/// Address encoding scheme.
46#[derive(PartialEq, Eq, Clone, Debug, Hash)]
47pub enum Scheme {
48    /// Base58 encoding.
49    Base58,
50    /// CashAddr encoding.
51    CashAddr,
52}
53
54/// Intepretation of the Hash160 bytes.
55#[derive(PartialEq, Eq, Clone, Debug, Hash)]
56pub enum HashType {
57    /// Public key hash
58    Key,
59    /// Script hash
60    Script,
61}
62
63/// Struct containing the bytes and metadata of a Bitcoin Cash address.
64/// This is yeilded during decoding or consumed during encoding.
65#[derive(PartialEq, Eq, Clone, Debug, Hash)]
66pub struct Address {
67    /// Address bytes
68    pub body: Vec<u8>,
69    /// Encoding scheme
70    pub scheme: Scheme,
71    /// Hash type
72    pub hash_type: HashType,
73    /// Network
74    pub network: Network,
75}
76
77/// Creates an empty `Address` struct, with the `body` bytes the empty vector,
78/// `Scheme::CashAddr`, `HashType::Key`, and `Network::Main`.
79impl Default for Address {
80    fn default() -> Self {
81        Address {
82            body: vec![],
83            scheme: Scheme::CashAddr,
84            hash_type: HashType::Key,
85            network: Network::Main,
86        }
87    }
88}
89
90impl Address {
91    /// Create a new address.
92    pub fn new(body: Vec<u8>, scheme: Scheme, hash_type: HashType, network: Network) -> Self {
93        Address {
94            body,
95            scheme,
96            hash_type,
97            network,
98        }
99    }
100
101    /// Borrow address bytes.
102    pub fn as_body(&self) -> &[u8] {
103        &self.body
104    }
105
106    /// Take address bytes.
107    pub fn into_body(self) -> Vec<u8> {
108        self.body
109    }
110
111    /// Attempt to convert the raw address bytes to a string.
112    pub fn encode(&self) -> Result<String, cashaddr::EncodingError> {
113        match self.scheme {
114            Scheme::CashAddr => CashAddrCodec::encode(
115                &self.body,
116                self.hash_type.to_owned(),
117                self.network.to_owned(),
118            ),
119            Scheme::Base58 => Ok(Base58Codec::encode(
120                &self.body,
121                self.hash_type.to_owned(),
122                self.network.to_owned(),
123            )
124            .unwrap()), // Base58 encoding is infallible
125        }
126    }
127
128    /// Attempt to convert an address string into bytes.
129    pub fn decode(
130        addr_str: &str,
131    ) -> Result<Self, (cashaddr::DecodingError, base58::DecodingError)> {
132        CashAddrCodec::decode(addr_str).or_else(|cash_err| {
133            Base58Codec::decode(addr_str).map_err(|base58_err| (cash_err, base58_err))
134        })
135    }
136}
137
138/// A trait providing an interface for encoding and decoding the `Address` struct for each address scheme.
139pub trait AddressCodec {
140    type EncodingError;
141    type DecodingError;
142
143    /// Attempt to convert the raw address bytes to a string.
144    fn encode(
145        raw: &[u8],
146        hash_type: HashType,
147        network: Network,
148    ) -> Result<String, Self::EncodingError>;
149
150    /// Attempt to convert the address string to bytes.
151    fn decode(s: &str) -> Result<Address, Self::DecodingError>;
152}