wagyu_bitcoin/
format.rs

1use crate::network::BitcoinNetwork;
2use wagyu_model::{AddressError, ExtendedPrivateKeyError, ExtendedPublicKeyError, Format};
3
4use serde::Serialize;
5use std::fmt;
6
7/// Represents the format of a Bitcoin address
8#[derive(Serialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[allow(non_camel_case_types)]
10pub enum BitcoinFormat {
11    /// Pay-to-Pubkey Hash, e.g. 1NoZQSmjYHUZMbqLerwmT4xfe8A6mAo8TT
12    P2PKH,
13    /// Pay-to-Witness-Script Hash, e.g. 347N1Thc213QqfYCz3PZkjoJpNv5b14kBd
14    P2WSH,
15    /// SegWit Pay-to-Witness-Public-Key Hash, e.g. 34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53
16    P2SH_P2WPKH,
17    /// Bech32, e.g. bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx
18    Bech32,
19}
20
21impl Format for BitcoinFormat {}
22
23impl BitcoinFormat {
24    /// Returns the address prefix of the given network.
25    pub fn to_address_prefix<N: BitcoinNetwork>(&self) -> Vec<u8> {
26        N::to_address_prefix(self)
27    }
28
29    /// Returns the format of the given address prefix.
30    pub fn from_address_prefix(prefix: &[u8]) -> Result<Self, AddressError> {
31        if prefix.len() < 2 {
32            return Err(AddressError::InvalidPrefix(prefix.to_vec()));
33        }
34        match (prefix[0], prefix[1]) {
35            (0x00, _) | (0x6F, _) => Ok(BitcoinFormat::P2PKH),
36            (0x05, _) | (0xC4, _) => Ok(BitcoinFormat::P2SH_P2WPKH),
37            (0x62, 0x63) | (0x74, 0x62) => Ok(BitcoinFormat::Bech32),
38            _ => return Err(AddressError::InvalidPrefix(prefix.to_vec())),
39        }
40    }
41
42    /// Returns the network of the given extended private key version bytes.
43    /// https://github.com/satoshilabs/slips/blob/master/slip-0132.md
44    pub fn from_extended_private_key_version_bytes(prefix: &[u8]) -> Result<Self, ExtendedPrivateKeyError> {
45        match prefix[0..4] {
46            [0x04, 0x88, 0xAD, 0xE4] | [0x04, 0x35, 0x83, 0x94] => Ok(BitcoinFormat::P2PKH),
47            [0x04, 0x9D, 0x78, 0x78] | [0x04, 0x4A, 0x4E, 0x28] => Ok(BitcoinFormat::P2SH_P2WPKH),
48            _ => Err(ExtendedPrivateKeyError::InvalidVersionBytes(prefix.to_vec())),
49        }
50    }
51
52    /// Returns the network of the given extended public key version bytes.
53    /// https://github.com/satoshilabs/slips/blob/master/slip-0132.md
54    pub fn from_extended_public_key_version_bytes(prefix: &[u8]) -> Result<Self, ExtendedPublicKeyError> {
55        match prefix[0..4] {
56            [0x04, 0x88, 0xB2, 0x1E] | [0x04, 0x35, 0x87, 0xCF] => Ok(BitcoinFormat::P2PKH),
57            [0x04, 0x9D, 0x7C, 0xB2] | [0x04, 0x4A, 0x52, 0x62] => Ok(BitcoinFormat::P2SH_P2WPKH),
58            _ => Err(ExtendedPublicKeyError::InvalidVersionBytes(prefix.to_vec())),
59        }
60    }
61}
62
63impl fmt::Display for BitcoinFormat {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        match self {
66            BitcoinFormat::P2PKH => write!(f, "p2pkh"),
67            BitcoinFormat::P2WSH => write!(f, "p2wsh"),
68            BitcoinFormat::P2SH_P2WPKH => write!(f, "p2sh_p2wpkh"),
69            BitcoinFormat::Bech32 => write!(f, "bech32"),
70        }
71    }
72}