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}